爬虫案例--网易新闻板块页面及详情抓取(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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具