爬虫案例--网易新闻板块页面及详情抓取(scrapy中间件+selenium)

需求:爬取网易新闻中的新闻数据(标题和内容)

页面分析:

--网页新闻页面板块名称非动态加载,解析板块名称和板块url

--板块页面对应的页面是动态加载的,解析新闻标题和新闻详情页url

--板块页面的新闻详情页里的内容非动态加载,解析新闻内容

解析分析:

--板块名称为非动态加载,通过scrapy正常获取解析

--板块页面信息动态加载,通过 scrapy下载器中间件+selenium 结合进行解析

--新闻详情页非动态加载,通过scrapy正常获取解析

selenium在scrapy中的使用流程:

--1.在爬虫类中实例化一个浏览器对象,将其作为爬虫类的一个属性

--2.在中间件中实现浏览器自动化相关的操作

--3.在爬虫类中重写closed(self,spider),在其内部关闭浏览器对象

 

# 爬虫文件news.py 

复制代码
import scrapy
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from wangyinews.items import WangyinewsItem


class NewsSpider(scrapy.Spider):
    name = 'news'
    # allowed_domains = ['www.xxx.com']
    start_urls = ['https://news.163.com/']
    t_url_list = []  # 存储板块的url

    # 要用到selenium,而且整个抓取过程,只要有一个浏览器就可以,因此用init方式实例化一个浏览器对象
    def __init__(self):
        self.service = Service('D:\pythonworks\spider\wangyinews\wangyinews\spiders\chromedriver.exe')
        self.options = webdriver.ChromeOptions()
        self.options.add_experimental_option('excludeSwitches',  ['enable-logging'])
        self.bro = webdriver.Chrome(service=self.service,options=self.options)

    # 解析news页面上板块的名称和url
    def parse(self, response):
        li_list = response.xpath('//*[@id="index2016_wrap"]/div[2]/div[2]/div[2]/div[2]/div//li')
        list_num = [2]
        for index in list_num:
            t_name = li_list[index].xpath('./a/text()')[0].extract()
            t_url = li_list[index].xpath('./a/@href')[0].extract()
            self.t_url_list.append(t_url)

        # 依次对每一个板块对应的页面进行请求
        for t_url in self.t_url_list:
            yield scrapy.Request(url=t_url, callback=self.parse_t)

    # 解析每一个板块页面中新闻的标题和新闻详情页的url
    # 板块页面的新闻是动态加载出来的,所以直接解析是解析不出来的,通过中间件结合selenium进行操作
    def parse_t(self, response):
        div_list = response.xpath('//div[@class="ndi_main"]/div')
        for div in div_list:
            news_title = div.xpath('.//h3[1]/a/text()').extract_first()
            news_detail_url = div.xpath('.//h3[1]/a/@href').extract_first()

            # 请求传参准备
            item = WangyinewsItem()
            item['news_title'] = news_title
            item['news_detail_url'] = news_detail_url

            # 对新闻详情页的url发起请求,及请求传参
            yield scrapy.Request(url=news_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['content'] = content
        yield item

    # 爬虫结束后关闭浏览器(重写了一个closed函数)
    def closed(self,spider):
        self.bro.quit()
复制代码

 

# middlewares.py

复制代码
from scrapy import signals
from itemadapter import is_item, ItemAdapter
from scrapy.http import HtmlResponse
from time import sleep
class WangyinewsDownloaderMiddleware: def process_request(self, request, spider): return None # 拦截板块对应的响应对象,进行篡改 def process_response(self, request, response, spider): # 获取在爬虫类中定义的浏览器对象 bro = spider.bro # 挑选出指定的响应对象进行修改,如果指定? # 通过url指定request,通过request确定response,一个request对应着一个response if request.url in spider.t_url_list: # 用selenium的bro浏览器对象发送请求获取包含动态数据的页面数据 bro.get(request.url) sleep(2) page_text = bro.page_source # 包含了动态加载的数据 # 针对定位到的板块response,篡改过程在这里 # 实例化一个新的响应对象(要包含动态加载的新闻数据),替代原来的response # HtmlResponse是scrapy内置的一个response构造函数,能够构建符合scrapy标准的response对象,包含四个参数 # 如何获取动态加载的数据? selenium new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request) return new_response else: return response def process_exception(self, request, exception, spider): pass def spider_opened(self, spider): spider.logger.info('Spider opened: %s' % spider.name)
复制代码

 

posted @   EricYJChung  阅读(201)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示