Какие способы оптимизации можно применить к этому коду?

Здравствуйте! У меня есть код для парсинга данных с сайта <a href="https://etender.gov.az/" rel="nofollow">https://etender.gov.az/</a>. Можете помочь мне разобраться с его работой? Вот сам код: <br/> <pre><code class="python">import requests
import pandas as pd
from concurrent.futures import ThreadPoolExecutor, as_completed
import time

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException

main_data = {
    'Organization_name': [],
    'Organization_voen': [],
    'Organization_address': [],
    'Event_name': [],
    'Event_number': [],
    'Classification_code': [],
    'Suggested_price': [],
    'Event_start_date': [],
    'Submission_deadline': [],
    'Envelope_opening_date': [],

    'Participation_fee': [],
    'Participation_description': [],

    'Usage_fee': [],
    'Usage_description': [],

    'Full_name': [],
    'Contact': [],
    'Position': [],
    'Phone_number': []
}

nested_data = {
    'Heading': [],
    'Disclosure': [],
    'Quantity': [],
    'Measure_unit': [],
    'Code': []
}

def get_total_items_from_link(api_link='https://etender.gov.az/api/events?EventType=2&amp;PageSize=1&amp;PageNumber=1&amp;EventStatus=1&amp;Keyword=&amp;buyerOrganizationName=&amp;PrivateRfxId=&amp;publishDateFrom=&amp;publishDateTo=&amp;AwardedparticipantName=&amp;AwardedparticipantVoen=&amp;DocumentViewType='):
    try:
        response = requests.get(api_link, timeout=20)
        if response.status_code == 200:
            data = response.json()
            return data['totalItems']
    except requests.Timeout
  • 15 сентября 2024 г. 19:23
Ответы на вопрос 2
Ваш код для парсинга данных с сайта имеет некоторые области, где можно повысить эффективность и улучшить его структуру. Рассмотрим несколько способов оптимизации:

### 1. Использование асинхронного выполнения
Если вы работаете с большим количеством запросов, можно рассмотреть использование `asyncio` и `aiohttp`, чтобы улучшить производительность путем выполнения нескольких запросов параллельно, не блокируя основной поток.

### 2. Улучшение обработки исключений
Текущая обработка исключений не завершает выполнение функции, если возникает ошибка. Можно добавить больше информации об исключении и, возможно, повторить попытку загрузки данных.

### 3. Избегание глобальных переменных
Попробуйте минимизировать использование глобальных переменных, чтобы улучшить читабельность кода и избежать потенциальных ошибок.

### 4. Использование `with` для работы с Selenium
Управление ресурсами WebDriver через конструкцию `with` гарантирует, что браузер будет правильно закрыт, даже если произойдет ошибка.

### 5. Снижение количества запросов
Проверьте, можно ли получить больше данных за один запрос (если API это позволяет), чтобы уменьшить общее количество запросов.

### Пример оптимизированного кода
Пример исправленного кода с применением некоторых упомянутых оптимизаций:

```python
import requests
import pandas as pd
from concurrent.futures import ThreadPoolExecutor
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoSuchElementException, TimeoutException

class TenderParser:
    def __init__(self):
        self.main_data = self.initialize_data_structure()
        self.nested_data = self.initialize_data_structure()

    def initialize_data_structure(self):
        return {
            'Organization_name': [],
            'Organization_voen': [],
            'Organization_address': [],
            # Другие поля...
        }

    def get_total_items_from_link(self, api_link):
        try:
            response = requests.get(api_link, timeout=20)
            response.raise_for_status()  # Проверка на ошибки HTTP
            data = response.json()
            return data.get('totalItems', 0)
        except (requests.Timeout, requests.RequestException) as e:
            print(f"Ошибка получения данных: {e}")
            return 0

    def parse_data(self, detail_link):
        with webdriver.Chrome() as driver:  # Используем with для управления ресурсами
            driver.get(detail_link)
            # Ваша логика парсинга...

    def run(self, api_link):
        total_items = self.get_total_items_from_link(api_link)
        with ThreadPoolExecutor(max_workers=10) as executor:
            futures = {executor.submit(self.parse_data, detail_link): detail_link for detail_link in self.get_detail_links(total_items)}
            for future in as_completed(futures):
                try:
                    future.result()  # Получаем результат, если нужно
                except Exception as e:
                    print(f"Ошибка при обработке: {e}")

    def get_detail_links(self, total_items):
        # Логика для получения полных ссылок на детали тендеров
        pass

if __name__ == "__main__":
    parser = TenderParser()
    parser.run('https://etender.gov.az/api/events?EventType=2&PageSize=1&PageNumber=1&EventStatus=1&Keyword=')
```

### Заключение
Эти оптимизации не только улучшат производительность и надежность вашего кода, но также повысят его читабельность и облегчите дальнейшее сопровождение.
Все не смотрел, но простыни типа: 
def get_contact(ids):
    for id in ids:
        template = f'https://etender.gov.az/api/events/{id}/contact-persons'
        try:
            response = requests.get(template, timeout=20)
            if response.status_code == 200:
                data_list = response.json()
                for data in data_list:
                    main_data['Full_name'].append(data.get('fullName', 'None') if data.get('fullName') else 'None')
                    main_data['Contact'].append(data.get('contact', 'None') if data.get('contact') else 'None')
                    main_data['Position'].append(data.get('position', 'None') if data.get('position') else 'None')
                    main_data['Phone_number'].append(data.get('phoneNumber', 'None') if data.get('phoneNumber') else 'None')

            else:
                main_data['Full_name'].append('None')
                main_data['Contact'].append('None')
                main_data['Position'].append('None')
                main_data['Phone_number'].append('None')
        except requests.Timeout:
            main_data['Full_name'].append('None')
            main_data['Contact'].append('None')
            main_data['Position'].append('None')
            main_data['Phone_number'].append('None')


пишутся гораздо проще. Да и структуру данных я бы поправил. К примеру простыня выше заменяется более лаконичным кодом:
main_data = []
...

def get_contact(ids):
    for id in ids:
    	current_data = {}
        template = f'https://etender.gov.az/api/events/{id}/contact-persons'
        try:
            response = requests.get(template, timeout=20)
            if response.status_code == 200:
                data_list = response.json()
                for (elem_to, elem_from) in [
                     ('Full_name', 'fullName'),
                     ('Contact', 'contact'),
                     ('Position', 'position'),
                     ('Phone_number', 'phoneNumber')
                ]:
                	current_data[elem_to] = data.get(elem_from, 'None')
         except requests.Timeout:
               pass
        main_data.apend()
Похожие вопросы