【问题标题】:Scraping Infinite Scrolling Pages with "load more" button using Scrapy使用 Scrapy 使用“加载更多”按钮抓取无限滚动页面
【发布时间】:2018-04-16 16:20:03
【问题描述】:

如何在响应为 html/text 而不是 json 的情况下报废无限滚动的网页。

我的第一次尝试是使用 Rule 和 LinkExtractor,这让我获得了大约 80% 的工作 url

class JobsetSpider(CrawlSpider):
    name = 'test'
    allowed_domains = ['jobs.et']
    start_urls = ['https://jobs.et/jobs/']

    rules = (
        Rule(LinkExtractor(allow='https://jobs.et/job/\d+/'), callback='parse_link'),
        Rule(LinkExtractor(), follow=True),
    )

    def parse_link(self, response):
        yield {
            'url': response.url
        }

我的第二次尝试是使用来自 SCRAPING INFINITE SCROLLING PAGES 的示例,但响应是 text/html 而不是 json。

当点击“加载更多”按钮时,我可以从 Chrome 开发工具上的网络中看到请求 url

https://jobs.et/jobs/?searchId=1509738711.5142&action=search&page=2

同时“页”数增加。

我的问题是

  1. 如何使用scrapy从响应头中提取上面的url 点击“加载更多”按钮
  2. 有没有更好的方法来解决这个问题?

【问题讨论】:

    标签: python python-3.x web-scraping scrapy


    【解决方案1】:

    忽略“加载更多”按钮。

    正如您所提到的,您可以使用 URL 访问所有工作页面。当您解析结果的第一页时,从标题元素中找到工作总数

    <h1 class="search-results__title ">
    268 jobs found
    </h1>
    

    该网站每页显示 20 个作业,因此您需要抓取 268/20 = 13.4(四舍五入为 14)页。

    当您完成第一个页面的解析后,创建一个生成器来为后续页面(最多 14 个循环)生成 URL,并使用另一个函数解析结果。您将需要 searchId,您无法从 URL 中获取它,但它位于页面上的隐藏字段中。

    <input type="hidden" name="searchId" value="1509738711.5142">
    

    使用它和页码,您可以构建您的网址

    https://jobs.et/jobs/?searchId=<id>&action=search&page=<page>
    

    是的,解析函数将与您的第一个页面解析器完全相同,但是当您完成所有工作时,最好忍受代码重复以保持头脑清醒。

    这个代码可能是这样的

    class JobsetSpider(CrawlSpider):
        ...
        start_urls = ['https://jobs.et/jobs/']
        ...
    
        def parse(self, response):
            # parse the page of jobs
            ...
            job_count = xpath(...)
            search_id = xpath(...)
            pages =  math.ceil(job_count / 20.0)
            for page in range(2, pages):
                url = 'https://jobs.et/jobs/?searchId={}&action=search&page={}'.format(search_id, page)
                yield Request(url, callback = self.parseNextPage)
    
        def parseNextPage(self, response):
            # parse the next and subsequent pages of jobs
            ...
    

    【讨论】:

    • 我明白了,谢谢,我只会将页面编辑到pages = math.ceil(job_count / 20.0) + 1,因为范围不包括结尾。
    【解决方案2】:

    您可以添加如下内容:

    has_next = response.css('.load-more').extract()
    if has_next:
        next_page = response.meta.get('next_page', 1) + 1
        url = response.urljoin(response.css('script').re_first("'(\?searchId.*page=)'") + str(next_page))
        yield Request(url , meta={'next_page': next_page})
    

    【讨论】:

    • 它返回正确的url格式但返回的url数是无限的。
    • hmm,您可以检查页面是否真正带来“新”数据,或者何时达到日期限制,或在元数据中发送当前看到的元素数量,并在您看到所有元素时停止(例如假设 268 就像 Tony 显示的那样并传递给元 268-20 等等(即:继续发出请求,直到达到 0)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2021-12-10
    • 1970-01-01
    • 2017-01-06
    • 2019-09-30
    • 2019-01-20
    相关资源
    最近更新 更多