Изучение Python с помощью таких проектов, как утилизация в сети, потрясающе. Вот как я познакомился с Python. Тем не менее, чтобы увеличить скорость утилизации, вы можете сделать три вещи:
- Измените анализатор HTML на что-то более быстрое. html.parser - самый медленный из них. Попробуйте изменить на «lxml» или «html5lib». (читай https://www.crummy.com/software/BeautifulSoup/bs4/doc/)
Удалите циклы и регулярные выражения, поскольку они замедляют ваш сценарий. Просто используйте инструменты BeautifulSoup, текст и полоску и найдите нужные теги (см. Мой скрипт ниже)
Поскольку узким местом в удалении веб-страниц обычно является ввод-вывод, ожидание получения данных с веб-страницы с использованием асинхронной или многопоточной обработки увеличит скорость. В приведенном ниже сценарии я использую многопоточность. Цель состоит в том, чтобы извлекать данные с нескольких страниц одновременно.
Так что, если мы знаем максимальное количество страниц, мы можем разделить наши запросы на несколько диапазонов и распределить их по пакетам :)
Пример кода:
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import requests
from bs4 import BeautifulSoup as bs
data = defaultdict(list)
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0'}
def get_data(data, headers, page=1):
# Get start time
start_time = datetime.now()
url = f'https://www.jobstreet.co.id/en/job-search/job-vacancy/{page}/?src=20&srcr=2000&ojs=6'
r = requests.get(url, headers=headers)
# If the requests is fine, proceed
if r.ok:
jobs = bs(r.content,'lxml').find('div',{'id':'job_listing_panel'})
data['title'].extend([i.text.strip() for i in jobs.find_all('div',{'class':'position-title header-text'})])
data['company'].extend([i.text.strip() for i in jobs.find_all('h3',{'class':'company-name'})])
data['location'].extend([i['title'] for i in jobs.find_all('li',{'class':'job-location'})] )
data['desc'].extend([i.text.strip() for i in jobs.find_all('ul',{'class':'list-unstyled hidden-xs '})])
else:
print('connection issues')
print(f'Page: {page} | Time taken {datetime.now()-start_time}')
return data
def multi_get_data(data,headers,start_page=1,end_page=20,workers=20):
start_time = datetime.now()
# Execute our get_data in multiple threads each having a different page number
with ThreadPoolExecutor(max_workers=workers) as executor:
[executor.submit(get_data, data=data,headers=headers,page=i) for i in range(start_page,end_page+1)]
print(f'Page {start_page}-{end_page} | Time take {datetime.now() - start_time}')
return data
# Test page 10-15
k = multi_get_data(data,headers,start_page=10,end_page=15)
Результаты:
Объяснение функции multi_get_data:
Эта функция будет вызывать функцию get_data в разных потоках с передачей нужных аргументов. На данный момент каждая ветка получает свой номер страницы для звонка. Максимальное количество рабочих установлено в 20, что означает 20 потоков. Вы можете увеличить или уменьшить соответственно.
Мы создали переменные данные, словарь по умолчанию, который принимает списки. Все потоки будут заполнять эти данные. Затем эту переменную можно преобразовать в json или Pandas DataFrame:)
Как вы видите, у нас есть 5 запросов, каждый из которых занимает менее 2 секунд, но общее количество по-прежнему меньше 2 секунд;)
Наслаждайтесь просмотром веб-страниц.