Scrapy + Splash: очистка элемента внутри внутреннего html

Я использую Scrapy + Splash для сканирования веб-страниц и пытаюсь извлечь данные из рекламных баннеров Google и других объявлений, и мне трудно получить scrapy, чтобы следовать в них по xpath.

Я использую Scrpay-Splash API для рендеринга страниц, чтобы их скрипты и изображения загрузить и сделать снимки экрана, но кажется, что рекламные баннеры Google создаются сценариями JS, которые затем вставляют свое содержимое в новый html-документ в iframe на веб-странице, например:  Красная область - это контейнер iframe, синяя показывает  ссылка, которую я хочу извлечь

Splash гарантирует, что код отображается, поэтому я не сталкиваюсь с обычной проблемой scrapy со сценариями, когда он читает содержимое сценария, а не результирующий html, но я не могу найти способ указать XPath, необходимый для добраться до нужных мне узлов элементов (ссылка href в объявлении).

Если я проверю элемент в Google и скопирую его xpath, он просто даст мне //*[@id="aw0"], который, как мне кажется, работал бы, если бы html iframe был всем, что здесь было, но он возвращает пустой, независимо от того, как я его пишу, и я чувствую, что это, вероятно, потому, что XPath не Не элегантно обрабатывают html-документы, уложенные в html-документы.

XPath для iframe, содержащего рекламный код Google, равен //*[@id="google_ads_iframe_/87824813/hola/blogs/home_0"] {числа постоянны}.

Есть ли способ сложить эти XPath вместе, чтобы scrapy проследовал по следу в нужный мне контейнер? Или мне следует анализировать объект ответа Splash напрямую каким-либо другим способом, и я не могу полагаться на Response.Xpath / Response.CSS для этого?


person ConnorU    schedule 20.06.2017    source источник
comment
Вы пытались открыть запрос в оболочке scrapy? См. этот вопрос SO и, в частности, ответ Михаила Коробова. Использование этого с view(response) должно дать вам больше шансов найти ошибку / проверить свой xpath.   -  person Casper    schedule 20.06.2017
comment
Ответ Михаила [на другой вопрос SO, с которым вы связались] кажется хорошим намеком в правильном направлении, к сожалению, я не понимаю, что он имеет в виду или как делать то, что он предлагает. Я попытался выполнить запрос в оболочке scrapy, но я вижу ответ, что содержимое iframe вообще не анализируется - что, как я понимаю, нормально, поскольку scrapy не отображает их, а splash делает. Я постараюсь посмотреть, смогу ли я сделать это на всплывающей оболочке.   -  person ConnorU    schedule 21.06.2017


Ответы (2)


Проблема в том, что содержимое iframe не возвращается как часть html. Вы можете либо попробовать получить содержимое iframe напрямую (по его src), либо использовать конечную точку render.json с опцией iframes = 1:

# ...
    yield SplashRequest(url, self.parse_result, endpoint='render.json', 
                        args={'html': 1, 'iframes': 1})

def parse_result(self, response):
    iframe_html = response.data['childFrames'][0]['html']
    sel = parsel.Selector(iframe_html)
    item = {
        'my_field': sel.xpath(...),
        # ...  
    }

/execute конечная точка не поддерживает получение содержимого iframe в версии Splash 2.3.3.

person Mikhail Korobov    schedule 21.06.2017
comment
Я получаю сообщение об ошибке sel = parsel.Selector (...). Это библиотека, которую мне нужно импортировать? - person ConnorU; 21.06.2017
comment
Да, вам нужно импортировать его (import parsel). Также обратите внимание, что xpath не должен включать ничего за пределами iframe - обрабатывайте содержимое iframe как отдельный документ. - person Mikhail Korobov; 21.06.2017
comment
Кроме того, вам может потребоваться другой iframe; Я написал для примера ['childFrames'][0] - индекс может быть другим. - person Mikhail Korobov; 21.06.2017
comment
Я не понимаю - вы имеете в виду, что выбранный вами числовой индекс ([0]) может быть другим или ['childFrames'] может называться по-другому? - person ConnorU; 21.06.2017
comment
Если на веб-странице есть несколько окон iframe, а интересующий вас iframe не первый, вам придется использовать соответствующий индекс вместо 0. - person Mikhail Korobov; 21.06.2017
comment
Ах, понял. В самом деле, это так, поэтому мне придется придумать, как их фильтровать, пока я не найду тот, который мне нужен. Я собираюсь поработать над этим, чтобы подтвердить это, но похоже, что это тот ответ, который мне нужен. Я приму его, как только закончу проверять, спасибо! - person ConnorU; 21.06.2017

Альтернативный способ борьбы с iframe может быть (ответ, если на главной странице):

    urls = response.css('iframe::attr(src)').extract()
    for url in urls :
            parse the url

таким образом iframe анализируется так, как будто это была обычная страница, но на данный момент я не могу отправить файлы cookie на главной странице в html внутри iframe, и это проблема

person chairam    schedule 20.07.2017