【问题标题】:How can I send Dynamic website content to scrapy with the html content generated by selenium browser?如何使用 selenium 浏览器生成的 html 内容将动态网站内容发送到scrapy?
【发布时间】:2022-01-10 10:37:52
【问题描述】:

我正在从事某些与股票相关的项目,我的任务是在过去 5 年中每天收集所有数据。即从 2016 年至今。我特别想到了使用 selenium,因为我可以使用爬虫和机器人来根据日期抓取数据。所以我使用了 selenium 的按钮单击,现在我希望 selenium 浏览器显示的相同数据由 scrappy 提供。 这是我现在正在处理的website。 我在 scrappy spider 中编写了以下代码。

class FloorSheetSpider(scrapy.Spider):
    name = "nepse"

    def start_requests(self):

        driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
        
     
        floorsheet_dates = ['01/03/2016','01/04/2016', up to till date '01/10/2022']

        for date in floorsheet_dates:
            driver.get(
                "https://merolagani.com/Floorsheet.aspx")

            driver.find_element(By.XPATH, "//input[@name='ctl00$ContentPlaceHolder1$txtFloorsheetDateFilter']"
                                ).send_keys(date)
            driver.find_element(By.XPATH, "(//a[@title='Search'])[3]").click()
            total_length = driver.find_element(By.XPATH,
                                               "//span[@id='ctl00_ContentPlaceHolder1_PagerControl2_litRecords']").text
            z = int((total_length.split()[-1]).replace(']', ''))    
            for data in range(z, z + 1):
                driver.find_element(By.XPATH, "(//a[@title='Page {}'])[2]".format(data)).click()
                self.url = driver.page_source
                yield Request(url=self.url, callback=self.parse)

               
    def parse(self, response, **kwargs):
        for value in response.xpath('//tbody/tr'):
            print(value.css('td::text').extract()[1])
            print("ok"*200)

更新:回答后的错误是

2022-01-14 14:11:36 [twisted] CRITICAL: 
Traceback (most recent call last):
  File "/home/navaraj/PycharmProjects/first_scrapy/env/lib/python3.8/site-packages/twisted/internet/defer.py", line 1661, in _inlineCallbacks
    result = current_context.run(gen.send, result)
  File "/home/navaraj/PycharmProjects/first_scrapy/env/lib/python3.8/site-packages/scrapy/crawler.py", line 88, in crawl
    start_requests = iter(self.spider.start_requests())
TypeError: 'NoneType' object is not iterable

我想将当前的 web html 内容发送到 scrapy feeder,但在过去 2 天里我遇到了异常错误,非常感谢任何帮助或建议。

【问题讨论】:

  • 你的意思是像this?
  • 什么是“异常错误”?
  • @DMalan 我无法提供 selenium 提供的当前浏览器的网页内容。scrapy 默认捕获初始页面。

标签: python selenium selenium-webdriver scrapy


【解决方案1】:

这两种解决方案并没有太大的不同。解决方案 #2 更适合您的问题,但请选择您喜欢的任何内容。

解决方案 1 - 使用来自驱动程序的 html 正文创建响应并立即将其抓取(您也可以将其作为参数传递给函数):

import scrapy
from selenium import webdriver
from selenium.webdriver.common.by import By
from scrapy.http import HtmlResponse


class FloorSheetSpider(scrapy.Spider):
    name = "nepse"

    def start_requests(self):

        # driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())
        driver = webdriver.Chrome()

        floorsheet_dates = ['01/03/2016','01/04/2016']#, up to till date '01/10/2022']

        for date in floorsheet_dates:
            driver.get(
                "https://merolagani.com/Floorsheet.aspx")

            driver.find_element(By.XPATH, "//input[@name='ctl00$ContentPlaceHolder1$txtFloorsheetDateFilter']"
                                ).send_keys(date)
            driver.find_element(By.XPATH, "(//a[@title='Search'])[3]").click()
            total_length = driver.find_element(By.XPATH,
                                               "//span[@id='ctl00_ContentPlaceHolder1_PagerControl2_litRecords']").text
            z = int((total_length.split()[-1]).replace(']', ''))
            for data in range(1, z + 1):
                driver.find_element(By.XPATH, "(//a[@title='Page {}'])[2]".format(data)).click()
                self.body = driver.page_source

                response = HtmlResponse(url=driver.current_url, body=self.body, encoding='utf-8')
                for value in response.xpath('//tbody/tr'):
                    print(value.css('td::text').extract()[1])
                    print("ok"*200)

        # return an empty requests list
        return []

解决方案 2 - 使用超级简单的下载器中间件:

(您在parse 方法中可能会有延迟,请耐心等待)。

import scrapy
from scrapy import Request
from scrapy.http import HtmlResponse
from selenium import webdriver
from selenium.webdriver.common.by import By


class SeleniumMiddleware(object):
    def process_request(self, request, spider):
        url = spider.driver.current_url
        body = spider.driver.page_source
        return HtmlResponse(url=url, body=body, encoding='utf-8', request=request)


class FloorSheetSpider(scrapy.Spider):
    name = "nepse"

    custom_settings = {
        'DOWNLOADER_MIDDLEWARES': {
            'tempbuffer.spiders.yetanotherspider.SeleniumMiddleware': 543,
            # 'projects_name.path.to.your.pipeline': 543
        }
    }
    driver = webdriver.Chrome()

    def start_requests(self):

        # driver = webdriver.Firefox(executable_path=GeckoDriverManager().install())


        floorsheet_dates = ['01/03/2016','01/04/2016']#, up to till date '01/10/2022']

        for date in floorsheet_dates:
            self.driver.get(
                "https://merolagani.com/Floorsheet.aspx")

            self.driver.find_element(By.XPATH, "//input[@name='ctl00$ContentPlaceHolder1$txtFloorsheetDateFilter']"
                                ).send_keys(date)
            self.driver.find_element(By.XPATH, "(//a[@title='Search'])[3]").click()
            total_length = self.driver.find_element(By.XPATH,
                                               "//span[@id='ctl00_ContentPlaceHolder1_PagerControl2_litRecords']").text
            z = int((total_length.split()[-1]).replace(']', ''))
            for data in range(1, z + 1):
                self.driver.find_element(By.XPATH, "(//a[@title='Page {}'])[2]".format(data)).click()
                self.body = self.driver.page_source
                self.url = self.driver.current_url

                yield Request(url=self.url, callback=self.parse, dont_filter=True)

    def parse(self, response, **kwargs):
        print('test ok')
        for value in response.xpath('//tbody/tr'):
            print(value.css('td::text').extract()[1])
            print("ok"*200)

请注意,我使用的是 chrome,所以将它改回 Firefox,就像在您的原始代码中一样。

【讨论】:

  • 谢谢你,我一定会试试这个解决方案会回复你
  • 如果我的项目名称是 first_scrapy,我的中间件路径是什么?
  • 如果它在蜘蛛内部(如答案)并且文件名是 spider.py(在答案中文件名是 Yetanotherspider.py),那么它将是:first_scrapy.spiders.spider.SeleniumMiddleware。但是最好把中间件类放在middlewares.py里面然后就是first_scrapy.middlewares.SeleniumMiddleware,我只是把它放在spider里面让你看得更清楚。
  • 你永远不会更新final_floor_sheet,所以它一直是空的。
  • start_requests:This method must return an iterable with the first Requests to crawl for this spider。在函数末尾发出一个虚拟请求,并使用pass 创建一个解析方法,应该没问题。 (如果您使用中间件,则不需要这样做)。
猜你喜欢
  • 2021-01-06
  • 2019-02-21
  • 2011-04-19
  • 2020-10-03
  • 2019-08-09
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 2017-04-05
相关资源
最近更新 更多