web-dev-qa-db-fra.com

sélénium avec scrapy pour la page dynamique

J'essaie d'extraire des informations sur les produits d'une page Web à l'aide de scrapy. Ma page Web à effacer ressemble à ceci:

  • commence par une page liste de produits avec 10 produits
  • un clic sur le bouton "Suivant" charge les 10 produits suivants (l'URL ne change pas entre les deux pages)
  • j'utilise LinkExtractor pour suivre chaque lien de produit dans la page du produit et obtenir toutes les informations dont j'ai besoin

J'ai essayé de reproduire le prochain bouton-appel-ajax mais je ne peux pas travailler, alors j'essaie Selenium. Je peux exécuter le WebDriver de Selenium dans un script séparé, mais je ne sais pas comment intégrer Scrapy. Où vais-je mettre la partie sélénium dans mon araignée raclante?

Mon araignée est assez standard, comme suit:

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

Toute idée est appréciée. Merci!

71
Z. Lin

Cela dépend vraiment de la manière dont vous devez gratter le site et des données que vous souhaitez obtenir.

Voici un exemple de suivi de la pagination sur eBay avec Scrapy + Selenium:

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()

Voici quelques exemples d '"araignées au sélénium":


Il existe également une alternative à l’utilisation de Selenium avec Scrapy. Dans certains cas, utiliser ScrapyJS middleware suffit à gérer les parties dynamiques d'une page. Exemple d'utilisation dans le monde réel:

102
alecxe

Si (l'URL ne change pas entre les deux pages), vous devez ajouter dont_filter = True avec votre scrapy.Request () ou scrapy trouvera cette url en double après le traitement de la première page.

Si vous avez besoin de rendre des pages avec JavaScript, vous devez utiliser scrapy-splash , vous pouvez également vérifier ceci middleware scrapy qui peut gérer les pages javascript avec Selenium ou vous pouvez le faire en lançant n'importe quel navigateur sans tête

Mais la solution la plus efficace et la plus rapide est d’examiner votre navigateur et de voir quelles demandes sont faites lors de la soumission d’un formulaire ou du déclenchement d’un événement donné. Essayez de simuler les mêmes requêtes que celles envoyées par votre navigateur. Si vous pouvez répliquer correctement les demandes, vous obtiendrez les données dont vous avez besoin.

Voici un exemple :

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))

Lorsque l'URL de la pagination est identique pour toutes les pages et utilise POST demande, vous pouvez utiliser scrapy.FormRequest () () au lieu de scrapy.Request () , les deux sont identiques mais FormRequest ajoute un nouvel argument ( formdata = ) au constructeur.

Voici un autre exemple d'araignée de cette post :

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
1
Expired Brain