Различное содержимое веб-страницы между запросами и aiohttp - PullRequest
1 голос
/ 08 января 2020

Я пытаюсь ускорить очистку веб-страниц, удалив блокирующий ввод / вывод, поэтому я решил изменить пакет запросов на aiohttp.

К сожалению, после перехода на aiohttp сайты, созданные с Angular, дают мне ответ без динамического c содержимого.

Итак, у меня есть следующие 2 вопроса:

  1. Почему модуль запросов дает мне надлежащее (отображаемое) содержимое, если он не запускается JS как селен, но aiohttp нет?
  2. Как я могу исправить код, чтобы получить правильный контент с aiohttp?
import aiohttp
import asyncio
import requests

URL = 'https://justjoin.it/'


async def fetch_async(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.text()


async def main():
    content_async = await fetch_async(URL)
    content_requests = requests.get(URL).text

    print('Are equal: ', content_async == content_requests)


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
finally:
    loop.close()

Ответы [ 2 ]

1 голос
/ 08 января 2020

Я решил свою проблему. Иэн предложил мне инициировать отправку заголовков на сервер, после игры с заголовками я обнаружил, что возвращаемое содержимое зависит от агента пользователя.

Когда я отправляю запрос aiohttp с помощью 'АГЕНТ-АГЕНТ': 'python -запросы /2.22.0 'Я получил обработанный контент, то же самое для' Google Bot ', но если для User-Agent было установлено значение' Python / 3.6 aiohttp / 3.6.2 'или' Firefox ', я получил не обработанный контент.

Таким образом, для некоторых пользовательских агентов сервер выполняет рендеринг на стороне сервера.

Решение:

async def fetch_async(url):
async with aiohttp.ClientSession() as session:
    async with session.get(url, headers={'User-Agent': 'python-requests/2.22.0'}) as resp:
        print('AIOHTTP headers: ', dict(resp.request_info.headers))
        return await resp.text()
0 голосов
/ 08 января 2020
  1. JavaScript - это рендеринг сайта на стороне клиента, который симулирует селен. С Selenium вы запускаете веб-драйвер, который загружает текущий веб-сайт и, таким образом, имитирует реального пользователя. Я ожидаю, что именно здесь проблема с aiohttp, что, судя по всему, ваш код не запускает веб-драйвер, поэтому JavaScript на странице никогда не сработает и, следовательно, никогда не будет отображаться.
  2. Я собираюсь предложить другое решение, чем использование aiohttp, потому что ваша общая цель заключается в повышении скорости очистки.

Предложение Существует модуль под названием Scrapy , который поможет вам параллельно выполнять очистку, переходить по ссылкам, очищать подстраницы и многое другое, что я определенно рекомендую.

Исправление загрузки JS страниц : используете ли вы aiohttp или scrapy, вам нужно будет смоделировать пользователя для JavaScript быть оказанным. Вот (Ура!) Другой модуль под названием Scrapy-Spla sh. Он включает в себя некоторую конфигурацию, и кривая обучения может показаться немного крутой для начала, однако, она поставляется со всем, что вам нужно при просмотре веб-страниц. Для настройки Spla sh я написал здесь еще один ответ очистить скрытые страницы, если поиск дает больше результатов, чем отображается . Я рекомендую взглянуть на это тоже.

Scrapy Spla sh может использоваться непосредственно aiohttp, согласно документации , однако, есть ряд проблем, которые не решаются таким образом, о котором заботится скрап.

Ниже приведен непроверенный пример того, как может выглядеть ваш Паук в Scrapy.

Использование Scrapy: Пример Spider (Не проверено)

import scrapy
from scrapy_splash import SplashRequest

class JustJoinSpider(scrapy.Spider):
    name = "justjoin"
    splash_args = {
        'html': 1,
        'png': 1,
        'width': 600,
        'render_all': 1,
        'wait': 0.5
    }
    def start_requests(self):
        urls = [
            'https://justjoin.it/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def start_requests(self):
        for url in self.start_urls:
            yield SplashRequest(url, self.parse, args=splash_args)

    def parse(self, response):
    # magic responses are turned ON by default,
    # so the result under 'html' key is available as response.body
    html = response.body

    # you can also query the html result as usual
    title = response.css('title').extract_first()
    company-name = response.css('company-name').extract_first()
    company-address = response.css('company-address').extract_first()

    # full decoded JSON data is available as response.data:
    png_bytes = base64.b64decode(response.data['png'])
...