Scrapy: response.body возвращает бессмысленный HTML (~ 95% времени).Пытаюсь поставить диагноз - PullRequest
0 голосов
/ 28 сентября 2019

Сводка проблемы

Я пытаюсь загрузить этот URL (https://www.glassdoor.com/Reviews/reviews-SRCH_IP2.htm) с помощью вызова метода yield scrapy.Request(url = url, callback = ...), а свойство response.body возвращает HTML, который совсем не напоминает HTMLЯ ожидаю возврата.

Выдержка из тела, которое возвращается в response.body :

<!DOCTYPE html>\n
<html lang=\'en\' xmlns:fb=\'http://www.facebook.com/2008/fbml\' xmlns:og=\'http://opengraph.org/schema/\'\n      class=\'flex\'>
   \n\n<head prefix=\'og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# glassdoor: http://ogp.me/ns/fb/glassdoor#\'><script src="https://browser.sentry-cdn.com/5.2.0/bundle.min.js" crossorigin="anonymous"></script><script>\n\t\n\tSentry.init(\n\t\t{\n\t\t\tdsn: \'https://a0ab694c43ba4fccafb5987e4a3e8367@sentry.glassdoor.com/8\',\n\t\t\tenvironment: \'prod\',\n\t\t\tsampleRate: 0.0\n\t\t}\n\t);\n\tSentry.configureScope(function(scope){\n\t\tscope.setUser(\n\t\t\t{\n\t\t\t\tid: \'0\',\n\t\t\t\tguid: \'0b8f8e55-d91d-4ea7-848a-0a3a1b215fc8\'\n\t\t\t}\n\t\t);\n\t});\n</script><!-- because the getter clears the value --><script>\n\twindow.gdGlobals = window.gdGlobals ||\n\t\t[{\n\t\t\t\'analyticsId\':

Полный текст приведенного выше HTML также несодержит содержимое тела, которое я пытаюсь очистить.

Выдержка из тела HTML при личном посещении URL :

<!DOCTYPE html>
<html lang='en' xmlns:fb='http://www.facebook.com/2008/fbml'xmlns:og='http://opengraph org/schema/'class='flex'>
   <head prefix='og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# glassdoor: http://ogp.me/ns/fb/glassdoor#'>
      <script src="https://browser.sentry-cdn.com/5.2.0/bundle.min.js" crossorigin="anonymous"></script><script>
         Sentry.init(
            {
                dsn: 'https://a0ab694c43ba4fccafb5987e4a3e8367@sentry.glassdoor.com/8',
                environment: 'prod',
                sampleRate: 0.0
            }
         );

Что я пытался

У меня есть другой паук (spider1, давайте назовем его), который успешно вызывает scrapy.Request() и возвращает ожидаемый HTML. Основное различие между spider1 и этим пауком заключается в том, что spider1 требует логин для доступа к информации.попытался запросить вышеуказанный URL-адрес как до, так и после входа в систему, но возвращенный HTML-код одинаков. Кроме того, Glassdoor не требует входа пользователя в систему для чтения содержимого URL-адреса, на который я ссылалсявыше, поэтому я не верю, что это является причиной проблемы.

Мой код и что странно

Код для вызова этого приведен ниже:

start_urls = ["https://www.glassdoor.com/Reviews/reviews-SRCH_IP2.htm"]
yield scrapy.Request(url = self.start_urls[0], callback = self.process_page) 

Странная часть в том, что при отладке HTML-код действительно возвращается правильно (но очень нечасто - я бы оценил, может быть, в 1/20 раза).Это происходит без каких-либо изменений кода , и я испытываю значительные трудности в определении причин, по которым это работает в тех редких случаях.

Мои мысли

Единственное слегка обоснованное подозрениеУ меня есть вот что мне нужно для реализации паук прокси.Glassdoor мог намеренно блокировать мои запросы, объясняя, почему HTML-код корректно возвращается только во время отладки - опять же, это происходит примерно через 1/20 выполнения, и он никогда не возвращался правильно без точек останова, ведущих к вызову scrapy.Request().

Большое спасибо за любые советы и / или указатели.С благодарностью!

Ответы [ 2 ]

2 голосов
/ 29 сентября 2019

На популярных сайтах, таких как Glassdoor, скорее всего, введено ограничение для сканеров, при таких обстоятельствах вам потребуется прокси-концентратор (IP-распространитель).

Как правило, в случае недопустимого ответа вы должны следить за:

  1. На некоторых сайтах только собственные IP-адреса (или IP-адреса определенной страны) могут иметь полный доступ к своим бизнес-ресурсам.
  2. Частота запросов.
  3. Запрос проверки заголовков (cookie, пользовательский агент).
  4. Подписанные запросы (в основном на мобильных устройствах).

В вашем случае, я могу сказать, что у Glassdoor есть ограничение по крайней мере.Используйте этот однострочный текст для проверки:

Linux

seq 1000 | xargs -i -P 18 sh -c 'curl -I -H "User-Agent: scrapybot" -s https://www.glassdoor.com/Reviews/reviews-SRCH_IP2.htm | grep HTTP'

Mac

seq 1000 | xargs -I {} -P 18 sh -c 'curl -I -H "User-Agent: scrapybot" -s https://www.glassdoor.com/Reviews/reviews-SRCH_IP2.htm | grep HTTP'

HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 200 OK
...
HTTP/1.1 200 OK
HTTP/1.1 429 Too Many Requests
HTTP/1.1 200 OK
HTTP/1.1 200 OK
HTTP/1.1 429 Too Many Requests
HTTP/1.1 200 OK
...
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests
HTTP/1.1 429 Too Many Requests

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

1 голос
/ 28 сентября 2019

Страница отображается с JavaScript и XHR.Так что вам нужно что-то, что может с этим справиться.Поэтому используйте

sudo pip3 install scrapy-selenium

Получите правильный драйвер для вашей операционной системы из https://github.com/mozilla/geckodriver/releases при использовании Firefox или другого драйвера при использовании другого браузера см. https://www.seleniumhq.org/download/

spider.py

import scrapy
from scrapy_selenium import SeleniumRequest


class Spider(scrapy.Spider):
    name = "spider"

    start_urls = ["https://www.glassdoor.com/Reviews/reviews-SRCH_IP2.htm"]

    def start_requests(self):
        yield SeleniumRequest(url=self.start_urls[0], callback=self.parse_result)

    def parse_result(self, response):
        for url in response.selector.css('span .url'):
            print(url)
        for title in response.selector.css('.tightAll'):
            print(title)

settings.py

# -*- coding: utf-8 -*-

BOT_NAME = 'spider'

SPIDER_MODULES = ['spider.spiders']
NEWSPIDER_MODULE = 'spider.spiders'


SELENIUM_DRIVER_NAME = 'firefox'
SELENIUM_DRIVER_EXECUTABLE_PATH = '/usr/local/bin/geckodriver'
SELENIUM_DRIVER_ARGUMENTS=['-headless']  # '--headless' if using chrome instead of firefox

ROBOTSTXT_OBEY = True



DOWNLOADER_MIDDLEWARES = {
    'scrapy_selenium.SeleniumMiddleware': 800
}

Выходы:

..
<Selector xpath="descendant-or-self::span/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' url ')]" data='<span class="url">www.pwc.com</span>'>
<Selector xpath="descendant-or-self::span/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' url ')]" data='<span class="url">www.primark.com</span>'>
<Selector xpath="descendant-or-self::span/descendant-or-self::*/*[@class and contains(concat(' ', normalize-space(@class), ' '), ' url ')]" data='<span class="url">www.ey.com</span>'>
<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' tightAll ')]" data='<a href="/Overview/Working-at-Tesco-E...'>
<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' tightAll ')]" data='<a href="/Overview/Working-at-J-Sains...'>
<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' tightAll ')]" data='<a href="/Overview/Working-at-NESTA-E...'>
<Selector xpath="descendant-or-self::*[@class and contains(concat(' ', normalize-space(@class), ' '), ' tightAll ')]" data='<a href="/Overview/Working-at-McDonal...'>
...

Подробнее см. https://docs.scrapy.org/en/latest/topics/dynamic-content.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...