前言
为了更加熟练的应用Scrapy,可以爬取一下网易新闻的导航栏各个模块的详情页内容试试手
1.下载Scrapy和selenium以及浏览器驱动,并将其初始化
想要了解selenium和scrapy可以去看看我之前的内容介绍
https://blog.youkuaiyun.com/Tudective/article/details/136853389?spm=1001.2014.3001.5502
https://blog.youkuaiyun.com/Tudective/article/details/136765867?spm=1001.2014.3001.5502
import scrapy
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from fiveBlood.items import FivebloodItem
class FiveSpider(scrapy.Spider):
name = "five"
start_urls = ["https://news.163.com/"]
# 储存导航栏模块的url
model_urls=[]
# 初始化浏览器对象
def __init__(self):
# 初始化浏览器
s = Service("D:\Program Files (x86)\chrome\chromedriver.exe")
self.bro = webdriver.Chrome(service=s)
1.1 setting.py基本设置
在setting.py 关闭ROBOTSTXT_OBEY和日志信息,填写USER_AGENTH和日志信息
ROBOTSTXT_OBEY = False
LOG_LEVEL='ERROR'
USER_AGENT="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 Edg/122.0.0.0"
2.定位爬取导航栏模块的URL
建立一个model_urls来储存爬取的url,通过F12和xpath定位到模块的标签,在循环通过request对模块发起请求
def parse(self, response):
# 定位导航栏各个模块的url
li_list=response.xpath('//*[@id="index2016_wrap"]/div[3]/div[2]/div[2]/div[2]/div/ul/li')
# 将需要爬取的导航栏模块的下标储存在列表中
alist=[1,2]
for index in alist:
model_url=li_list[index].xpath('./a/@href').extract_first()
self.model_urls.append(model_url)
# 向爬取的url发起请求,并回调到parse_model()方法中
for url in self.model_urls:
yield scrapy.Request(url=url,callback=self.parse_model)
3.获取新闻URL和标题
首先通过F12发现标题和响应详情页内容URL结构层次,都在一个DIV标签内,然后便通过xpath定位,并将其储存到item对象中
item对象中所存储的值
import scrapy
class FivebloodItem(scrapy.Item):
# define the fields for your item here like:
# 设置item中储存的response的内容
title = scrapy.Field()
content = scrapy.Field()
# pass
然后就要将item数据传递到详情页中去
# 解析每个版面中新闻的内容和标题
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()
new_detail_url=div.xpath('./a/@href').extract_first()
# 创建item对象,将数据解析到item中去
item=FivebloodItem()
item['title']=title
# 通过meta参数,把item这个字典只给‘key’,将parse_model的response传递给parse_detail中去
yield scrapy.Request(url=new_detail_url,callback=self.parse_detail,meta={'item':item})
4.获取详情页的内容
这里注意一下extract()和extract_first()的区别,由于内容里边可能第一个列表不会包含全部的内容,所以使用extract()返回内容列表
# 解析新闻内容
def parse_detail(self, response):
# extract():这个方法返回的是一个数组list,,里面包含了多个string,如果只有一个string,则返回['ABC']这样的形式。
# extract_first():这个方法返回的是一个string字符串,是list数组里面的第一个字符串。
content=response.xpath('//*[@id="content"]/div[2]//text()').extract()
# 将列表内容转换为字符串
content=" ".join(content)
# 消除里边的空格和换行符
content=content.replace('\n', '').replace('\r', '')
# 储存到item中去
item=response.meta['item']
item['content']=content
# 最终将所有response存储到item中,由item提交到管道类中去
yield item
在详情页网址中的去F12定位到内容的标签地址
然后关闭一下开始创建的浏览器对象
# 关闭浏览器对象
def closed(self,spider):
self.bro.quit()
5.在中间件中拦截响应
详情页的内容可能是动态数据,可以对发起的请求进行拦截,scrapy有五大核心模块,想要了解可以去看看
https://blog.youkuaiyun.com/Tudective/article/details/136952793?spm=1001.2014.3001.5502
from scrapy import signals
# useful for handling different item types with a single interface
from itemadapter import is_item, ItemAdapter
from time import sleep
import random
from scrapy.http import HtmlResponse
class FivebloodDownloaderMiddleware:
# 拦截请求
def process_request(self, request, spider):
return None
# 拦截响应
def process_response(self, request, response, spider):
# 获取在five文件中创建的爬虫类中的浏览器对象
bro=spider.bro
# 挑选出指定的响应对象进行更改,即各个模块的url
if request.url in spider.model_urls:
bro.get(request.url)
# 浏览器停留等待防止,防止加载过快,未解析到数据
sleep(5)
# 包含动态数据
page_text=bro.page_source
# HtmlResponse作为Response构造方法,能够对HTML内容进行解析
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
然后在setting.py文件中打开这几个管道类
6.对数据进行持久化储存
在pipelines.py文件去执行储存操作
from itemadapter import ItemAdapter
class FivebloodPipeline:
fp = None
# 对爬取的数据进行储存
# 重写一个父类的方法:该方法只会在开始爬虫的时候执行一次
def open_spider(self, spider):
print("开始爬虫》》》》")
# 保存在当前文件WyNews.txt中
self.fp = open('./WyNews.txt', 'w', encoding='utf-8')
def process_item(self, item, spider):
title = item['title']
content = item['content']
self.fp.write(title + ':' + content + '\n')
# 传递给下一个即将被执行的管道类
return item
def close_spider(self, spider):
print("结束爬虫》》》》")
self.fp.close()
7.运行爬取
在命令行cd切换到自己的项目路径,输入scrapy crawl ‘项目名‘ ,回车运行
期间就能看到selenium和scrapy对数据进行爬取
最后是爬取的结果