селен с scrapy для динамической страницы

Я пытаюсь очистить информацию о продукте с веб-страницы с помощью scrapy. Моя веб-страница, которую нужно очистить, выглядит так:

  • начинается со страницы product_list с 10 продуктами
  • нажатие на кнопку «Далее» загружает следующие 10 продуктов (URL-адрес между двумя страницами не меняется)
  • Я использую LinkExtractor, чтобы переходить по каждой ссылке продукта на страницу продукта и получать всю необходимую информацию

Я попытался воспроизвести ajax-call следующей кнопки, но не могу работать, поэтому я пробую селен. Я могу запустить selenium webdriver в отдельном скрипте, но я не знаю, как интегрироваться с scrapy. Куда мне поместить селен в мой паук для скрапинга?

Мой паук довольно стандартный, вроде следующего:

class ProductSpider(CrawlSpider):
    name = "product_spider"
    allowed_domains = ['example.com']
    start_urls = ['http://example.com/shanghai']
    rules = [
        Rule(SgmlLinkExtractor(restrict_xpaths='//div[@id="productList"]//dl[@class="t2"]//dt'), callback='parse_product'),
        ]

    def parse_product(self, response):
        self.log("parsing product %s" %response.url, level=INFO)
        hxs = HtmlXPathSelector(response)
        # actual data follows

Любая идея приветствуется. Спасибо!


person Z. Lin    schedule 31.07.2013    source источник
comment
stackoverflow.com / questions / 50714354 /   -  person Yash Pokar    schedule 06.06.2018


Ответы (2)


Это действительно зависит от того, как вам нужно очистить сайт и как и какие данные вы хотите получить.

Вот пример того, как вы можете следить за разбивкой на страницы на ebay, используя _1 _ + _ 2_:

import scrapy
from selenium import webdriver

class ProductSpider(scrapy.Spider):
    name = "product_spider"
    allowed_domains = ['ebay.com']
    start_urls = ['http://www.ebay.com/sch/i.html?_odkw=books&_osacat=0&_trksid=p2045573.m570.l1313.TR0.TRC0.Xpython&_nkw=python&_sacat=0&_from=R40']

    def __init__(self):
        self.driver = webdriver.Firefox()

    def parse(self, response):
        self.driver.get(response.url)

        while True:
            next = self.driver.find_element_by_xpath('//td[@class="pagn-next"]/a')

            try:
                next.click()

                # get the data and write it to scrapy items
            except:
                break

        self.driver.close()

Вот несколько примеров «селеновых пауков»:


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

person alecxe    schedule 31.07.2013
comment
Спасибо за вашу помощь. На самом деле моя самая большая проблема - это часть после next.click (). Каждый раз, когда я получаю новую страницу, могу ли я использовать LinkExtractor для извлечения всех URL-адресов продуктов, а затем использовать обратный вызов для их анализа? - person Z. Lin; 01.08.2013
comment
Есть ли способ повторно использовать ответ, который уже был получен scrapy, вместо использования self.driver.get(response.url)? - person Ethereal; 23.09.2013
comment
@ Z.Lin - проблема, которую вы описали, все еще существует? Если вы ее решили, не могли бы вы поделиться решением? Спасибо. Кроме того, подумайте о том, чтобы принять ответ, если это помогло. - person alecxe; 27.06.2014
comment
@Ethereal Боюсь, это накладные расходы. Но хороший момент. - person alecxe; 27.06.2014
comment
Для установки в ubuntu: sudo pip install selenium. Чтобы скрыть окно браузера: установите и пример в этом сообщении. - person KrisWebDev; 08.11.2014
comment
привет @ alecxe .. У меня был очень похожий вопрос на stackoverflow.com/questions/28420078/, что вам подходит ... если у вас есть время, пожалуйста, взгляните на него - person Amistad; 10.02.2015
comment
Если бы мы использовали этот код. Разве не лучше полностью использовать селен? Я имею в виду, что scrapy здесь ничего не делает - person Halcyon Abraham Ramirez; 20.06.2015
comment
@HalcyonAbrahamRamirez, это всего лишь пример селеновой части в пауке scrapy. После того, как селен завершен, обычно self.driver.page_source передается в экземпляр Selector для Scrapy для анализа HTML, формирования экземпляров элементов, передачи их конвейерам и т. Д. Или файлы cookie селена могут быть проанализированы и переданы в Scrapy для выполнения дополнительных запросов. Но если вам не нужна мощь архитектуры фреймворка scrapy, тогда, конечно, вы можете использовать только селен - он сам по себе довольно эффективен для определения местоположения элементов. - person alecxe; 20.06.2015
comment
@alecxe да, пока я понял концепцию. Я все еще запутался в той части, где вы извлекаете источник страницы с помощью селена и передаете элементы, которые хотите очистить, в scrapy. Например. Есть кнопка «Загрузить еще», нажатие на нее покажет больше элементов, но вы извлечете xpath для этих элементов. теперь, как передать эти xpath в scrapy? потому что только элементы, показанные при первом запросе страницы, будут проанализированы scrappy, а не те, которые были после нажатия кнопки `` Загрузить больше '' с селеном - person Halcyon Abraham Ramirez; 20.06.2015
comment
@HalcyonAbrahamRamirez понял, я бы загрузил больше предметов, пока больше нечего будет добавлять. Затем возьмите driver.page_source и передайте его Selector() .. - person alecxe; 20.06.2015
comment
Хорошо, я получил вроде бы спасибо @alecxe, последний вопрос. используя этот подход с селеном и загружая больше элементов и прочего. Можно ли использовать класс паука обхода для извлечения информации из вновь загруженных элементов? - person Halcyon Abraham Ramirez; 20.06.2015
comment
@HalcyonAbrahamRamirez, мне нужна дополнительная информация и я посмотрю ваш код. Не могли бы вы создать отдельный вопрос, чтобы больше людей могли вам помочь? Спасибо. - person alecxe; 20.06.2015
comment
Я бы сделал, если бы мог, но мне запретили задавать вопросы. Трахни меня. в любом случае спасибо за уделенное время: D - person Halcyon Abraham Ramirez; 20.06.2015
comment
Делаем это без лома с драйвером Selenium. Условие не выполняется после перехода на вторую страницу. Как заставить его щелкать? - person Volatil3; 04.07.2015
comment
@alecxe Воспользовавшись вашим советом, я получаю TypeError: невозможно создать слабую ссылку на объект 'unicode' .. Я никогда не видел этого раньше - есть помощь? - person Benjamin James; 17.03.2016
comment
@BenjaminJames, это не связано с самим ответом. Попробуйте погуглить или задать отдельный вопрос здесь, в SO. - person alecxe; 17.03.2016
comment
@alecxe, я получаю следующую ошибку ([4960:6000:0612/235425.186:ERROR:shader_disk_cache.cc(237)] Failed to create shader cache entry: -2). Подскажите, пожалуйста, что я делаю не так, если я покажу вам свой сценарий?!?! кто-нибудь? - person oldboy; 13.06.2018

Если (URL-адрес не меняется между двумя страницами), тогда вы должны добавить dont_filter = True с вашим scrapy.Request () или scrapy найдет этот URL-адрес как дубликат после обработки первой страницы.

Если вам нужно отображать страницы с помощью javascript, вы должны использовать scrapy-splash, вы также можете проверить это промежуточное программное обеспечение scrapy, которое может обрабатывать javascript страницы, использующие селен, или вы можете сделать это, запустив любой безголовый браузер

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

Вот пример:

class ScrollScraper(Spider):
    name = "scrollingscraper"

    quote_url = "http://quotes.toscrape.com/api/quotes?page="
    start_urls = [quote_url + "1"]

    def parse(self, response):
        quote_item = QuoteItem()
        print response.body
        data = json.loads(response.body)
        for item in data.get('quotes', []):
            quote_item["author"] = item.get('author', {}).get('name')
            quote_item['quote'] = item.get('text')
            quote_item['tags'] = item.get('tags')
            yield quote_item

        if data['has_next']:
            next_page = data['page'] + 1
            yield Request(self.quote_url + str(next_page))

Когда URL-адрес разбивки на страницы одинаков для всех страниц и использует запрос POST, вы можете использовать scrapy.FormRequest () вместо scrapy.Request (), оба одинаковы, но FormRequest добавляет новый аргумент (formdata =) конструктора.

Вот еще один пример паука из этого сообщения:

class SpiderClass(scrapy.Spider):
    # spider name and all
    name = 'ajax'
    page_incr = 1
    start_urls = ['http://www.pcguia.pt/category/reviews/#paginated=1']
    pagination_url = 'http://www.pcguia.pt/wp-content/themes/flavor/functions/ajax.php'

    def parse(self, response):

        sel = Selector(response)

        if self.page_incr > 1:
            json_data = json.loads(response.body)
            sel = Selector(text=json_data.get('content', ''))

        # your code here

        # pagination code starts here
        if sel.xpath('//div[@class="panel-wrapper"]'):
            self.page_incr += 1
            formdata = {
                'sorter': 'recent',
                'location': 'main loop',
                'loop': 'main loop',
                'action': 'sort',
                'view': 'grid',
                'columns': '3',
                'paginated': str(self.page_incr),
                'currentquery[category_name]': 'reviews'
            }
            yield FormRequest(url=self.pagination_url, formdata=formdata, callback=self.parse)
        else:
            return
person muhive    schedule 27.04.2019