scrapy配合selenium爬取需要反复操作同一个动态页面的方法,解决点击“下一页”但是URL相同的网站

首先这种网站一定要设置爬取的速率,目标网站用这种方式写入网页估计是被爬虫搞怕了,大概率有更简单的反爬方法,因此爬取速率要注意。博主要爬的网站是一个电影网站:艺恩,点击下一页可以看到其实执行了一个js拿数据,但是URL却没有任何变化,我们需要一路下一页下一页点下去,然后把展示出的电影详情也搞到。

爬取思路:

  1. 启动selenium,控制Chrome开两个标签页,第一个标签页显示主页,第二个标签页显示不同的电影详情页
  2. 如果是需要点击下一步的,就先跳转到第一个tab,然后点击“下一步”,把网页信息传回去。
  3. 如果要显示电影详情页,就跳转到第二个tab,然后把网页信息传回去。

代码:

  1. 首先是爬虫文件spider的编写
# -*- coding: gbk -*-
from scrapy.spiders import CrawlSpider
import scrapy
from urllib.parse import urljoin


class MovieDetailSpider(CrawlSpider):
    name = "flim"
    allowed_domains = ["endata.com.cn"]
    
    def start_requests(self):
        start_url = 'https://www.endata.com.cn/BoxOffice/MovieStock/movies.html'
        self.page = 1 # 当前主页的页面
        self.max_page = 500 # 预期爬取的最大页面,这个可以往大调整,目的是及时退出循环。
        yield scrapy.Request(start_url, self.parse, dont_filter=True, meta={
            'page': self.page,
        })

    def parse(self, response):
    	# 这里是拿到详情页后的函数
    	# 1. 提取出这个页面中出现的电影,然后传给movie_detail_page方法提取电影详情页的内容
        li_movie_list = response.css('ul.movies-list-box li')
        for li_movie_info in li_movie_list[:2]:
            relative_url = li_movie_info.css('a::attr(href)').extract_first()
            relative_url = relative_url.strip()
            movie_url = urljoin(response.url, relative_url)
            yield scrapy.Request(movie_url, callback=self.movie_detail_page,
                                 dont_filter=False)  # when you run, turn to True
        # 重要!这是个 死循环/递归 操作,把详情页的URL继续发送给middleware,回调自己,以方便再次从页面中提取电影列表
        start_url = 'https://www.endata.com.cn/BoxOffice/MovieStock/movies.html'
        self.page += 1
        if self.page < self.max_page:
            yield scrapy.Request(start_url, self.parse, dont_filter=True, meta={
                'page': self.page,
            })
        # next page begin

    def movie_detail_page(self, response):
        movie_dict = {}
        # 这是个提取电影详情页的函数,提取出来内容yield给pipeline保存就行
        yield movie_dict
  1. middleware 文件:
class HandlessMiddleware(object):

    def __init__(self):
    	# 在构造方法里创建Chrome窗口与两个标签页
        super(HandlessMiddleware, self).__init__()
        option = webdriver.ChromeOptions()
        option.add_argument('headless')
        prefs = {
            "profile.managed_default_content_settings.images": 2,  # 禁止加载图片
            'permissions.default.stylesheet': 2,  # 禁止加载css
        }
        option.add_experimental_option("prefs", prefs)
        self.browser = webdriver.Chrome(chrome_options=option)
        self.browser.implicitly_wait(5)
        self.browser.execute_script('window.open("","_blank");') # 新建一个标签页

	# 每个URL都会被送到这里,所以要根据不同的url判断
	# 1. 定位到哪一个标签页
	# 2. 是抓取传来的URL还是点击下一页
    def process_request(self, request, spider):
    	# 如果是首页url,意味着要点击“下一页”
        if request.url == 'https://www.endata.com.cn/BoxOffice/MovieStock/movies.html':
        	# 如果是第一次爬取,那么需要把首页抓下来
            if request.meta['page'] == 1:
                self.browser.switch_to.window(self.browser.window_handles[0])
                self.browser.get(request.url)
                self.max_page = int(self.browser.find_element_by_id('TableList_Paging').find_element_by_css_selector(
                    'a.layui-laypage-last').text) # 这个是首页分了多少页,也就是要点多少次“下一页”
            else:
            	# 如果不是第一次遇到首页url,意味着不需要抓取这个url,而是点击“下一页”
                self.browser.switch_to.window(self.browser.window_handles[0])
                if request.meta['page'] <= self.max_page:
                    print("MAIN PAGE CHANGE : " + str(request.meta['page']) + " / " + str(self.max_page))
                    self.browser.find_element_by_id('TableList_Paging').find_element_by_class_name(
                        'layui-laypage-next').click()  # get next page
                else:
                    return None
        else:
        	# 这是遇到了电影详情页的url,切换到第2个标签页然后得到详情页内容,传回去,传给哪个函数是由第一个文件spider里callback指定的,middleware只需要不择手段拿到网页内容即可。
            print("NEW PAGE GET : " + request.url)
            self.browser.switch_to.window(self.browser.window_handles[1])
            self.browser.get(request.url)
            time.sleep(2)
        return HtmlResponse(url=self.browser.current_url, body=self.browser.page_source, encoding="utf-8",request=request)
  1. 在setting中注册
ROBOTSTXT_OBEY = False
COOKIES_ENABLED = False

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.useragent.UsserAgentMiddleware': None,
    'movie_data.middlewares.HandlessMiddleware': 200,
}
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
当使用 ScrapySelenium 结合进行网页动态加载数据的爬取时,可以按照以下步骤进行操作: 1. 安装所需库:确保已安装 ScrapySelenium 库。可以使用以下命令进行安装: ``` pip install scrapy pip install selenium ``` 2. 创建 Scrapy 项目:使用以下命令创建一个新的 Scrapy 项目: ``` scrapy startproject dynamic_scraping ``` 3. 创建 Spider:进入项目目录,并使用以下命令创建一个新的 Spider: ``` cd dynamic_scraping scrapy genspider example example.com ``` 这将在 `spiders` 目录下创建一个名为 `example.py` 的 Spider。 4. 配置 Spider:打开 `example.py` 文件,并按照以下示例进行配置: ```python import scrapy from scrapy_selenium import SeleniumRequest from scrapy.selector import Selector class ExampleSpider(scrapy.Spider): name = 'example' allowed_domains = ['example.com'] def start_requests(self): yield SeleniumRequest( url='https://example.com', callback=self.parse ) def parse(self, response): sel = Selector(response) # 在这里使用 XPath 或 CSS 选择器提取动态加载的数据 # 示例:提取标题 title = sel.xpath('//h1/text()').get() print(title) ``` 在上面的示例中,我们使用了 `SeleniumRequest` 替代了普通的 `scrapy.Request`,这使得 Scrapy 可以使用 Selenium 来处理动态加载的内容。 5. 配置 Selenium:为了使用 Selenium,你需要配置相关的 Web 驱动程序。根据你使用的浏览器,下载并安装相应的驱动程序,并将其添加到系统的 PATH 环境变量中。 6. 运行 Spider:使用以下命令运行 Spider: ``` scrapy crawl example ``` 这将启动爬取过程,并在控制台上打印出提取的动态加载数据。 通过以上步骤,你可以使用 ScrapySelenium 结合进行爬取动态加载数据的操作。你可以根据实际需求修改 Spider 中的代码来提取所需的数据,并将其保存到文件或数据库中。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆萌的代Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值