Здравствуйте! У меня есть код для парсинга данных с сайта <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&PageSize=1&PageNumber=1&EventStatus=1&Keyword=&buyerOrganizationName=&PrivateRfxId=&publishDateFrom=&publishDateTo=&AwardedparticipantName=&AwardedparticipantVoen=&DocumentViewType='):
try:
response = requests.get(api_link, timeout=20)
if response.status_code == 200:
data = response.json()
return data['totalItems']
except requests.Timeout
Ваш код для парсинга данных с сайта имеет некоторые области, где можно повысить эффективность и улучшить его структуру. Рассмотрим несколько способов оптимизации:
### 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=')
```
### Заключение
Эти оптимизации не только улучшат производительность и надежность вашего кода, но также повысят его читабельность и облегчите дальнейшее сопровождение.
Все не смотрел, но простыни типа: <br/> <pre><code class="python">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')</code></pre> <br/> <br/> пишутся гораздо проще. Да и структуру данных я бы поправил. К примеру простыня выше заменяется более лаконичным кодом: <br/> <pre><code class="python">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()</code></pre>