中间件——爬取网易新闻内容

中间件:

  • 下载中间件
    • 位置:引擎和下载器之间
    • 作用:批量拦截到整个工程中所有的请求和响应
    • 拦截请求:
      • UA伪装:process_request
      • 代理IP:process_exception:return request
    • 拦截响应:
      • 篡改响应数据,响应对象
      • 需求:爬取网易新闻中的新闻数据(标题和内容)
        • 1.通过网易新闻的首页解析出五大板块对应的详情页的url(没有动态加载)
        • 2.每一个板块对应的新闻标题都是动态加载出来的(动态加载)
        • 3.通过解析出每一条新闻详情页的url获取详情页的页面源码,解析出新闻内容

需求分析

由于要解析不同新闻板块、每个新闻的标题和新闻详情信息,而这些又不是在一个url,所以需要使用三个parse函数进行解析。

由于每一个新闻板块的ur里面的新闻标题都是动态加载出来的,所以需要使用selenium才能得到动态加载出的数据。
那么如何在scrapy中使用selenium呢?
具体的实现方法就是:使用中间件对发起请求的响应数据进行拦截,并将响应数据修改为已动态加载数据的response响应。 如果我发起的url是我需要发起的url,那就对响应数据进行拦截,然后将用selenium得到的响应数据进行作为response返回,达到以假乱真的效果。

如何在scrapy中使用selenium?

在爬虫文件wangyi.py中,在类中初始化时,初始化一个浏览器对象,这样可以保证这个浏览器对象只产生了一次。

同时也要重写父类的关闭操作,将浏览器关闭。

python 复制代码
class WangyiSpider(scrapy.Spider):
    name = "wangyi"
    # allowed_domains = ["www.xxx.com"]
    start_urls = ["https://news.163.com/"]
    model_url_list = []     # 得到国内、国际、军事、航空四大模块的url

    def __init__(self):
        # 实例化一个浏览器对象
        options = webdriver.ChromeOptions()
        options.add_experimental_option("excludeSwitches", ["enable-logging"])
        serivce = Service(executable_path='E:\\python\爬虫\\7章:动态加载数据处理\\chromedriver.exe')
        self.browser = webdriver.Chrome(service=serivce, options=options)

	# 重写父类的关闭操作
	def closed(self, spider):
    self.browser.quit()

解析新闻板块url、新闻标题、新闻详情页url

python 复制代码
    def parse(self, response):
        li_list = response.xpath('//*[@id="index2016_wrap"]/div[3]/div[2]/div[2]/div[2]/div/ul/li')     # 得到所有的li标签
        # print("li_list:\n", li_list)
        my_list = [1, 2]     # 下标是从0开始的,只解析国内国际的
        for i in my_list:
            model_url = li_list[i].xpath('./a/@href').extract_first()
            self.model_url_list.append(model_url)
        # print(self.model_url_list)
        for url in self.model_url_list:
            yield scrapy.Request(url=url, callback=self.parse_model)

    def parse_model(self, response):
        # 解析每个模块下的新闻标题
        div_list = response.xpath("/html/body/div/div[3]/div[3]/div[1]/div[1]/div/ul/li/div/div")
        for div in div_list:
            title = div.xpath('.//h3/a/text()').extract_first()
            detail_url = div.xpath('.//h3/a/@href').extract_first()

            item = WangyiproItem()
            item['title'] = title
            yield scrapy.Request(url=detail_url, callback=self.parse_detail, meta={'item':item})

    def parse_detail(self, response):
        # 解析每个新闻详情页下的文字
        content = response.xpath('//*[@id="content"]/div[2]//text()').extract()
        content = ''.join(content)
        item = response.meta['item']
        item['content'] = content
        yield item

处理下载中间件,修改响应数据。

这里修改响应数据是在process_response()函数中实现的。

那么我如何判断我当前发起的url是否是我需要发起selenium动态加载数据的url呢?

上面提到的类WangyiSpider 其实是一个spider类的子类。同时也对应def process_response(self, request, response, spider): 中的spider。所以将需要发起请求的url放到spider类中作为一个类变量,然后通过spider.model_url_list 就可以得到所有我需要发起selenium动态加载数据的url。

python 复制代码
class WangyiSpider(scrapy.Spider):
    name = "wangyi"
    # allowed_domains = ["www.xxx.com"]
    start_urls = ["https://news.163.com/"]
    model_url_list = []     # 得到国内、国际 二大模块的url


# middlewares.py
class WangyiproDownloaderMiddleware:
	# .....
	    def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.
        # 将爬虫中的实例化浏览器对象取出
        browser = spider.browser
        if request.url in spider.model_url_list:	# 如果发起的请求是在spider.model_url_list中,就使用selenium请求动态数据。
            browser.get(request.url)
            sleep(3)
            page_text = browser.page_source     # 包含了动态加载数据的页面
            # 实例化新的响应对象(此响应对象拥有selenium的动态加载的数据),然后返回这个新的响应对象
            new_response = HtmlResponse(url=response.url, body=page_text  encoding='utf-8', request=request)
            return new_response
        else:
            return response

别忘记在settings.py中开启下载中间件

python 复制代码
DOWNLOADER_MIDDLEWARES = {
   "wangyiPro.middlewares.WangyiproDownloaderMiddleware": 543,
}
相关推荐
VidDown1 小时前
24fps 转 25fps 不只是改个数字:帧率转换、PAL/NTSC 与音频补偿
python·网络协议·音视频·视频编解码·视频
死磕音视频3 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
凤山老林3 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
pride.li5 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
databook5 小时前
用 Pydantic AI 从零搭建一个能干活的 AI Agent
人工智能·python
顽疲5 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
康小旺5 小时前
把 markitdown 做成 Windows 桌面版:拖进文档就出 Markdown,附 233MB→64MB 打包裁剪全过程
python
Wang's Blog6 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
启观川6 小时前
数据结构与算法-第 3 章 常用算法-贪心算法
数据结构·笔记·python·算法·贪心算法
南笙北梦6 小时前
本地开源大模型多轮对话显存泄漏排查与修复实录
python