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

中间件:

  • 下载中间件
    • 位置:引擎和下载器之间
    • 作用:批量拦截到整个工程中所有的请求和响应
    • 拦截请求:
      • 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,
}
相关推荐
databook1 小时前
Manim实现闪光轨迹特效
后端·python·动效
Juchecar3 小时前
解惑:NumPy 中 ndarray.ndim 到底是什么?
python
用户8356290780513 小时前
Python 删除 Excel 工作表中的空白行列
后端·python
Json_3 小时前
使用python-fastApi框架开发一个学校宿舍管理系统-前后端分离项目
后端·python·fastapi
数据智能老司机10 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
数据智能老司机11 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机11 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机11 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i11 小时前
drf初步梳理
python·django
每日AI新事件11 小时前
python的异步函数
python