【问题标题】:Scrapy crawl every link after authenticationScrapy在身份验证后抓取每个链接
【发布时间】:2020-10-21 07:43:10
【问题描述】:

简介

由于我的爬虫或多或少已经完成,我需要重做一个只爬取整个域的链接的爬虫,我需要这个来完成我的工作。 抓取每个链接的蜘蛛应该每月运行一次。

我正在运行 scrapy 2.4.0,我的操作系统是 Linux Ubuntu server 18.04 lts

问题

我要爬的网站改变了他们的“隐私”,所以你必须先登录才能看到产品,这就是我的“linkcrawler”不再工作的原因。 我已经设法登录并抓取了我所有的东西,但 start_urls 在 csv 文件中给出。

代码

import scrapy
from ..items import DuifItem
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.http import FormRequest, Request
from scrapy_splash import SplashRequest

class DuifLinkSpider(CrawlSpider):
    name = 'duiflink'
    allowed_domains = ['duif.nl']
    login_page = 'https://www.duif.nl/login'
    start_urls = ['https://www.duif.nl']
    custom_settings = {'FEED_EXPORT_FIELDS' : ['Link']}
    
    def start_requests(self):
        yield SplashRequest(
        url=self.login_page,
        callback=self.parse_login,
        args={'wait': 3},
        dont_filter=True    
        )
    
    rules = (
       Rule(LinkExtractor(deny='https://www.duif.nl/nl/'), callback='parse_login', follow=True), 
    )
   
    def parse_login(self, response):
        return FormRequest.from_response(
            response,
            formid='login-form',
            formdata={
                'username' : 'not real',
                'password' : 'login data'},
            clickdata={'type' : 'submit'}, 
            callback=self.after_login)
        
    def after_login(self, response):
        accview = response.xpath('//ul[@class="nav navbar-nav navbar-secondary navbar-right"]//a/@href')[13]
        if accview:
            print('success')
        else:
            print(':(')
            
        for url in self.start_urls:
            yield response.follow(url=url, callback=self.search_links)
            
    def search_links(self, response):
        link = response.xpath('//ul[@class="nav navbar-nav navbar-secondary navbar-right"]/li/a/@href').get()
        
        for a in link:
            link = response.url
            yield response.follow(url=link, callback=self.parse_page)
                   

    def parse_page(self, response):
        productpage = response.xpath('//div[@class="product-details col-md-12"]')
        
        if not productpage:
            print('No productlink', response.url)
            
        for a in productpage:
            items = DuifItem()
            items['Link'] = response.url
            yield items

很遗憾,我无法提供一个虚拟帐户,您可以在其中尝试自己登录,因为它是一个 b2b 服务网站。

我可以想象我的“def search_links”是错误的。

我的计划结构是:

  1. 访问 login_page,传递我的登录凭据
  2. 检查是否通过 xpath 登录,它会检查是否提供了注销按钮。
  3. 如果登录,它会打印“成功”
  4. 由 xpath 表达式给出,它应该开始跟随链接:
  5. 通过访问每个链接,它应该通过xpath xpression检查是否给出了特定的容器,因此它知道它是否是一个产品页面。
  6. 如果是产品页面,保存访问过的链接,如果不是产品页面,则取下一个链接

控制台输出

如您所见,身份验证正在运行,但之后不会执行任何操作。

更新

我对我的代码做了一些修改:

import scrapy
from ..items import DuifItem
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from scrapy.http import FormRequest, Request
from scrapy_splash import SplashRequest

class DuifLinkSpider(CrawlSpider):
    name = 'duiflink'
    allowed_domains = ['duif.nl']
    login_page = 'https://www.duif.nl/login'
    start_urls = ['https://www.duif.nl/']
    custom_settings = {'FEED_EXPORT_FIELDS' : ['Link']}
    
    def start_requests(self):
        yield SplashRequest(
        url=self.login_page,
        callback=self.parse_login,
        args={'wait': 3},
        dont_filter=True    
        )
    
    rules = (
       Rule(LinkExtractor(), callback='parse_login', follow=True), 
    )
   
    def parse_login(self, response):
        return FormRequest.from_response(
            response,
            formid='login-form',
            formdata={
                'username' : 'not real',
                'password' : 'login data'},
            clickdata={'type' : 'submit'}, 
            callback=self.after_login)
        
    def after_login(self, response):
        accview = response.xpath('//ul[@class="nav navbar-nav navbar-secondary navbar-right"]//a/@href')[13]
        if accview:
            print('success')
        else:
            print(':(')
            
        for url in self.start_urls:
            yield response.follow(url=url, callback=self.search_links, dont_filter=True)
            
    def search_links(self, response):
        # link = response.xpath('//ul[@class="nav navbar-nav navbar-secondary navbar-right"]/li/a/@href')
        link = response.xpath('//a/@href')
        
        for a in link:
            link = a.get()
            link = 'https://www.duif.nl' + link if link else link
            yield response.follow(url=link, callback=self.parse_page, dont_filter=True)

    def parse_page(self, response):
        productpage = response.xpath('//div[@class="product-details col-md-12"]')
        
        if not productpage:
            print('No productlink', response.url)
            
        for a in productpage:
            items = DuifItem()
            items['Link'] = response.url
            yield items

现在我知道,我确实已经登录了,但它没有遵循“子”链接,但我想如果我使用 response.xpath('//a/@href') ,它会自动搜索整个 dom 的每个链接。

在我的新控制台输出下方

【问题讨论】:

    标签: python python-3.x xpath scrapy web-crawler


    【解决方案1】:

    登录后,您将返回解析您的起始网址。默认情况下,Scrapy 会过滤掉重复的请求,因此在您的情况下它会停在这里。您可以通过在请求中使用“dont_filter=True”来避免这种情况,如下所示:

    yield response.follow(url=url, callback=self.search_links, dont_filter=True)
    

    【讨论】:

    • 嘿@Wim,感谢您的回答。我添加了 dont_filter=True,现在我进入了我的控制台“No productlink duif.nl/about-duif/privacy-statement”并且它停止了 :( 为什么他们会竭尽全力让爬行变得如此困难 :D
    • 当您的 xpath for prouctpage 没有给您任何结果时,您会打印出一条消息。我无法在没有登录的情况下自己测试它,但最好用 scrapy shell 打开页面并检查是否可以在其中找到 product_page。如果它是动态加载的,则必须检查是否有额外的 api 请求完成,或者数据是否存在于 HTML 中的某处(通常是 json 结构)。
    • 是的,你是对的,但我想我的问题是它没有正确地跟随链接。我已经提前说谢谢,并会检查一些事情:) 我稍后会分享我的结果
    猜你喜欢
    • 1970-01-01
    • 2013-11-11
    • 2014-08-16
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多