利用scrapy爬取整站小说
今天带大家实践一把爬取整站小说,当然只是出于学习目的,大家千万不要应用于商业应用,因为可能出现侵权问题。本教程默认大家已经安装了scrapy,并且熟悉python语法。我们将逐步解析网站,然后将小说爬取保存到本地。
1.分析网页
通过点击查看各个网页的目录结构发现,小说的各个类目的网页结构都是一致的,所以我们只要能解析一个类目,那么基本所有的类目都可以解析,那么我们就暂时解析玄幻类目,解析完毕后,将其他类目加入爬取队列即可全站爬取。那么我们接下来就开始爬取
2.创建项目
使用scrapy命令创建项目,创建项目需要两条命令:
代码语言:javascript复制//创建项目,最后一个参数为项目名称
>> scrapy startproject xiaoshuoSpider
//创建网站爬虫,参数分别为爬虫名称,爬取的目标网址
>>scrapy genspider biqugeu 'https://www.biqugeu.net/'
这样我们就创建成功了一个项目,项目的目录结构如下:
爬虫的初始化代码为:
start_urls就是我们要爬取的链接,大家可以看到这是一个列表,所以我们可以放多个链接,所以,我们用分类目录替换掉现在这个链接,
代码语言:javascript复制start_urls = ["https://www.biqugeu.net/xuanhuanxiaoshuo/"]
然后接下来解析页面,打开f12开发者工具,如下图所示,我们可以清晰的看到目录结构,然后我们发现小说都是存在在li中,所以接下来我们只需要解析这个li标签就可以了,接下来我们写解析代码:
代码语言:javascript复制 def parse(self, response):
#解析a标签,得到小说名和详情章节目录页面地址
booklist=response.xpath('//ul/li/span[@class="s2"]/a')
#循环爬取到的小说,将其章节目录页的链接存放入scrapy的爬取队列
for i in booklist:
#章节目录页的url链接,
href="https://www.biqugeu.net/" i.xpath("./@href").extract_first()
#小说名称
book_name=i.xpath("string(.)").extract_first()
request= scrapy.Request(href,callback=self.parse_detail,dont_filter=True)
#将书名传递给下一个解析函数
request.meta["book_name"]=book_name
yield request
接下来解析章节目录页面
同样打开f12,观察目录结构,我们发现所有的章节信息都在list这个div里面,每一个dd就是一个章节,但是开头有最新章节与正文中的章节肯定是重复的部分,所以如果全部解析的话,那么肯定会出现重复的部分,可能需要通过去重去处理,但是我的本意是将小说保存到本地,保存的目录结构应该为一个小说一个文件夹,每一章都是一个文件名,基于文件名的唯一性,有重复的小说进来,会覆盖写入,所以这里不会出现重复问题。
但是,假如是存储于数据库,是需要做重复性校验的。
代码语言:javascript复制 def parse_detail(self,response):
#解析章节目录列表
chapterList=response.xpath('//div[@id="list"]/dl/dd/a')
#循环获取章节目录信息
for i in chapterList:
href="https://www.biqugeu.net" i.xpath("./@href").extract_first()
chapter_name=i.xpath("string(.)").extract_first()
# 向下解析详情页
request = scrapy.Request(href, callback=self.parse_content, dont_filter=True)
request.meta["book_name"]=response.meta["book_name"]
request.meta["chapter_name"]=chapter_name
yield request
通过观察详情页信息,会发现,文章的正文都在content中,那么我们只需要把content中的文本信息解析出来即可,
代码语言:javascript复制 def parse_content(self,response):
#此处需要使用extract().是因为本身xpath解析出来是一个列表,我们需要把列表中的所有数据取出来
content=response.xpath('//div[@id="content"]').xpath("string(.)").extract()
# 将list以换行符分割,转换成字符串
content="n".join(content)
# 将结果存入item,传到pipline里进行存储
item=XiaoshuospiderItem()
item["content"]=content
item["book_name"]=response.meta["book_name"]
item["chapter_name"]=response.meta['chapter_name']
yield item
将数据保存到本地
代码语言:javascript复制import os
class XiaoshuospiderPipeline:
def __init__(self):
self.result="result/"
def process_item(self, item, spider):
# 获取传递过来的数据
book_name=item["book_name"]
chapter_name=item["chapter_name"]
content=item["content"]
# 判断文件夹是否已经创建
if not os.path.exists(self.result book_name):
os.makedirs(self.result book_name)
# 判断章节是否已经爬取,未爬取,则写入
if not os.path.exists(self.result book_name "/" chapter_name):
with open(self.result book_name "/" chapter_name,"w") as f:
f.write(content)
return item
然后利用scrapy命令启动
代码语言:javascript复制scrapy crawl biqugeu
然后我们会发现小说已经爬取下来了,结果如下图:
想要获取源码,关注微信公众号:会呼吸的Coder,回复:6893