Студенты, которые слышали об асинхронных сканерах, должны были слышать о них более или менее.aiohttp
эта библиотека. Он поставляется с Pythonasync/await
Реализован асинхронный гусеничный гусеничный.
Используя aiohttp, мы можем написать краулер с параллелизмом, который конкурирует со Scrapy через API запросов.
Мы находимся в официальной документации aiohttp и видим, что она дает пример кода, как показано на следующем рисунке:
Теперь давайте немного изменим его, чтобы увидеть, насколько эффективно краулер написан таким образом.
Модифицированный код выглядит следующим образом:
import asyncio
import aiohttp
template = 'http://exercise.kingname.info/exercise_middleware_ip/{page}'
async def get(session, page):
url = template.format(page=page)
resp = await session.get(url)
print(await resp.text(encoding='utf-8'))
async def main():
async with aiohttp.ClientSession() as session:
for page in range(100):
await get(session, page)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Этот код посещает мою тренировочную станцию краулера 100 раз для 100 страниц контента.
Вы можете посмотреть его в действии с видео ниже:
![](король тогда-1257411235.cos.AP-Чэнду. Нет денег cloud.com/slow.2019-1… 22_51_37.gif)
Можно сказать, что текущая скорость работы почти ничем не отличается от однопоточного краулера, написанного запросами, а кодов гораздо больше.
Итак, как правильно высвободить суперсилу aiohttp?
Теперь изменим код:
import asyncio
import aiohttp
template = 'http://exercise.kingname.info/exercise_middleware_ip/{page}'
async def get(session, queue):
while True:
try:
page = queue.get_nowait()
except asyncio.QueueEmpty:
return
url = template.format(page=page)
resp = await session.get(url)
print(await resp.text(encoding='utf-8'))
async def main():
async with aiohttp.ClientSession() as session:
queue = asyncio.Queue()
for page in range(1000):
queue.put_nowait(page)
tasks = []
for _ in range(100):
task = get(session, queue)
tasks.append(task)
await asyncio.wait(tasks)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
В измененном коде я позволил сканеру просканировать 1000 страниц контента, давайте посмотрим на видео ниже.
![](Король SO -1257411235.COS.AP-Чэнду. Нет денег cloud.com/fast.2019-1 ... 22_49_49.gif)
Видно, что эта скорость уже может быть коэффициентом скребковым. И всем нужно знать, что у этого краулера всего 1 процесс, который достигает такой скорости за счет асинхронности.
Итак, после изменения кода, почему скорость стала намного выше?
Код ключа находится в:
tasks = []
for _ in range(100):
task = get(session, queue)
tasks.append(task)
await asyncio.wait(tasks)
В медленной версии у нас работает только 1 сопрограмма. В текущей быстрой версии мы создаем 100 сопрограмм и отправляем их вasyncio.wait
для единого расписания.asyncio.wait
Он вернется, когда все сопрограммы закончатся.
Мы помещаем 1000 URL-адресов вasyncio.Queue
В сгенерированной асинхронной очереди каждый COROUTINE постоянно вытесняет URL-адреса от асинхронной очереди, в то время как истина и доступа к ним доступа до тех пор, пока асинхронная очередь пуста и выходит.
Когда программа запущена, Python автоматически запланирует эти 100 сопрограмм. Когда сопрограмма ожидает возврата сетевого ввода-вывода, она переключается на вторую сопрограмму и инициирует запрос. Когда эта сопрограмма ожидает возврата, она продолжает переключаться на третья сопрограмма, сопрограмма и инициировать запрос... . Программа полностью использует время ожидания сетевого ввода-вывода, что значительно повышает скорость работы.
Наконец, я хотел бы поблагодарить стажера Сяохэ за этот ускоренный план.