Python爬取网站小说实战

本篇博客介绍一下通过Python爬取小说的一个案例:

首先我们选定一个网站的小说,这里我们选择的目标小说域名:http://m.ppxs.net/

我们的目标书籍是:《规则怪谈,欢迎来到甜蜜的家》

实现的思路:

我们伪装成浏览器,对小说网站进行访问,然后解析网站的元素,获取我们想要的部分,并存储到文档中汇总

基本要求:

获取书籍的名称,章节的名称,还有小说的正文部分

第一阶段:爬取小说网站的所有元素:

第一步:伪装成浏览器

(备注:现在需要安装有requests模块)

首先打开小说的首页:

观察小说的首页

第二步:检查一下网站的元素:

步骤:鼠标右键 -> 检查 

网页的源代码

第三步:我们点击上方栏中的“网络”,获取自己浏览器的User-Agent和Cookie属性,用于伪装,你可以理解为校园里的学生证,只有拥有学生证的学生才被允许访问学校

获取自己浏览器的User-Agent和Cookie属性

第四步:编写请求头代码,你可以理解为伪造一个学生证?

其中的User-Agent和Cookie属性则填写上自己浏览器的内容

至于Host填写的是网站的域名,Connection是选择一种策略模式,在此不细讲

import requests

headers = {
   'User-Agent': '......',
   'Cookie': '......',
   'Host': 'm.ppxs.net',

   'Connection': 'keep-alive'
}

第一阶段剩下的代码如下:

# 小说主页的网站,用于获取书籍名称

main_url = "https://www.a1x.net/book/69664"

# 用get方法获取网页元素
main_resp = requests.get(main_url, headers=headers)
# 将网页元素按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

# 检查是否成功获取网站元素
print(main_text)

第二阶段:爬取小说网站指定元素:

从现在开始,我们将使用lxml模块,请自行下载哦~

这部分代码很简单,只是在第一阶段的代码后面添加上指向即可

按照上图的步骤,复制指定内容的XPath

至于这里的XPath,你可以理解为信息的地址,you can try to 粘贴到一个文本框里,你会发现复制的是一串节点:/html/head/title

代码如下:

from lxml import etree

.................第一阶段代码...................

# 将文本内容创建为可解析元素

main_html = etree.HTML(main_text)

# main_html.xpath返回的是列表,这里用[0]来输出不带括号的纯净的元素

# 学习者可以去掉[0]来对比一下输出结果的差异

# 这里在/html/head/title后面添加了/text()指令,意思是获取文本,后同

bookTitle = main_html.xpath('/html/head/title/text()')[0]

# 输出结果以验证
print(bookTitle)

通过以上代码,就可以使用xpath方法获取书籍的名称了

现在整理一下前两个阶段所有的代码吧

import requests
from lxml import etree
# # 网络请求头,这里相当于模拟浏览器进行访问,不然绝大多数的网站拒绝你的访问
# # 这里的几种属性,User-Agent和Cookie是通过网页检查源代码来找出来的
headers = {
   'User-Agent': '......',
   'Cookie': '......',
   'Host': 'm.ppxs.net',
   'Connection': 'keep-alive'
}

# 小说主页网站
main_url = "https://www.a1x.net/book/69664"
# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)
# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')
# 将文本内容创建为可解析元素
main_html = etree.HTML(main_text)
# main_html.xpath返回的是列表,因此需要加一个[0]来表示列表中的首个元素
bookTitle = main_html.xpath('/html/head/title/text()')[0]
# 输出结果以验证
print(bookTitle)

第三阶段:爬取小说部分正文:

现在我们进入第三阶段,开始爬取正文部分了!!点击进入小说网站的第一章

第一步:获取小说章节名

第二步:通过相同的方法,获取章节名称
和其中一句正文的XPath地址

代码如下:

import requests
from lxml import etree
# 请求头
headers = {
   'User-Agent': '......',
   'Cookie': '......',
   'Host': 'm.ppxs.net',
   'Connection': 'keep-alive'
}

# 更改网络地址为当前页面

url = 'http://m.ppxs.net/read/63769/1177002.html'

# 使用get方法请求网页
resp = requests.get(url, headers=headers)
# 将网页内容按utf-8规范解码为文本形式
text = resp.content.decode('utf-8')

# 将文本内容创建为可解析元素,获取章节名称
html = etree.HTML(text)
title = html.xpath('/html/body/div[3]/text()')[0]

contents = html.xpath('//*[@id="nr1"]/p[1]/text()')[0]

# 检查是否获取正确

print(title)

print(contents)

最后输出的效果如上

第四阶段:爬取小说一整章正文:

此处,我自己在写代码的时候发现一个重要的问题:这些正文都是分割成一段一段一行一行的了,我不可能给每一行都弄个Xpath出来

正文都是分割好了的

我尝试用正文的上方<div id=''nr1''>的XPath地址,却发现行不通,找不到正文(笔者能力有限对不起)

所以我没有多考虑,想到了课堂上教过的一种方法:正则表达式

我使用正则表达式对元素进行了匹配,具体原理请自行查阅资料学习哦~

(记得下载正则表达式re模块)

第四阶段完整代码如下:

import requests
import re
from lxml import etree


# 浏览器请求头
headers = {
   'User-Agent': '......',
   'Cookie': '......',
   'Host': 'm.ppxs.net',
   'Connection': 'keep-alive'
}

# 小说主页,获取书籍名称
main_url = "http://m.ppxs.net/book/63769/"
main_resp = requests.get(main_url, headers=headers)
main_text = main_resp.content.decode('utf-8')
main_html = etree.HTML(main_text)
Title = main_html.xpath('//*[@id="content"]/div/div[1]/div[2]/p[1]/text()')[0]
print(Title)

# 正文页面链接,用XPath获取章节标题,用正则表达式获取章节正文
url = 'http://m.ppxs.net/read/63769/1177002.html'
resp = requests.get(url, headers)
text = resp.content.decode('utf-8')
html = etree.HTML(text)
title = html.xpath('/html/body/div[3]/text()')[0]
contents = re.findall('<p>(.*?)</p>', resp.text)

print(title)
print(contents)

# 创建并且把爬取到的东西写入文件,注意这里的策略是'a'而不能是'w'

# 否则后面每爬取新页面的正文时,就会覆盖原来已经爬取好的内容

# \n是用来换行的,保持页面美观整齐

with open(Title + '.txt', 'a', encoding='utf-8') as f:
   f.write(title)
   f.write('\n')
   for content in contents:
       f.write(content)
       f.write('\n')
   f.close()

参数说明

实现效果如上图

第五阶段:爬取小说一整章正文:

我们现在需要写一个功能,让Python可以获取下一页的链接,然后自己翻页自动继续爬取

初步的代码如下:(具体原理自己学习python爬虫之xpath解析哦~)

# 获取"下一页"按钮指向的链接

html = etree.HTML(text)
next_url_element = html.xpath('//*[@id="pt_next1"]/@href')[0]

但是这上面两行代码获取的网址缺少域名,比如下面这样的:

/read/63769/1177002_2.html

所以修改后的代码如下:

# 获取"下一页"按钮指向的链接
html = etree.HTML(text)
next_url_element = html.xpath('//*[@id="pt_next1"]/@href')[0]
print(next_url_element)
head = "http://m.ppxs.net"
new_url = head + next_url_element

第六阶段:爬取全部小说内容

根据前辈的指示,爬虫不能爬取得太快,否则可能触发网站的防护机制

因此咱们用time模块设置一下时间间隔,同时用random模块随机设定一下爬取的间隔时间,记得下载这两个模块哦~

源代码如下:(由于爬取整个小说内容量太大,这里仅爬取一部分)

import requests
from lxml import etree
import time
import random
import re

# 请求头,需要添加你的浏览器信息才可以运行
headers = {
   'User-Agent': '......',
   'Cookie': '......',
   'Host': 'm.ppxs.net',
   'Connection': 'keep-alive'
}

# 小说主页网址
main_url = "http://m.ppxs.net/book/63769/"

# 使用get方法请求网页
main_resp = requests.get(main_url, headers=headers)

# 将网页内容按utf-8规范解码为文本形式
main_text = main_resp.content.decode('utf-8')

# 将文本内容创建为可解析元素
main_html = etree.HTML(main_text)

Title = main_html.xpath('//*[@id="content"]/div/div[1]/div[2]/p[1]/text()')[0]

# 调试期间仅爬取六个页面
maxPages = 6
cnt = 0

# 爬取起点
url = 'http://m.ppxs.net/read/63769/1177002.html'

# 爬取终点
endurl = 'http://m.ppxs.net/read/63769/1177013.html'

while url != endurl:
   cnt += 1  # 记录当前爬取的页面
   if cnt > maxPages:
       break  # 当爬取的页面数cnt超过maxPages时停止

   resp = requests.get(url, headers=headers)
   text = resp.content.decode('utf-8')
   html = etree.HTML(text)
   title = html.xpath('/html/body/div[3]/text()')[0]
   contents = re.findall('<p>(.*?)</p>', resp.text)
   print(title)
   print(contents)

   with open(Title + '.txt', 'a', encoding='utf-8') as f:
       f.write(title)
       f.write('\n')
       for content in contents:
           f.write(content)
           f.write('\n')
       f.close()

   # 获取"下一页"按钮指向的链接
   html = etree.HTML(text)
   next_url_element = html.xpath('//*[@id="pt_next1"]/@href')[0]
   head = "http://m.ppxs.net"
   new_url = head + next_url_element

   # 传入函数next_url得到下一页链接
   url = new_url

   # 产生一个2~4之间的随机数
   sleepTime = random.randint(2, 4)

   # 暂停2~4之间随机的秒数
   time.sleep(sleepTime)

print("爬取完毕")

实现的效果验证

爬取的txt文档

备注:

源代码基于文章:python爬虫实战——小说爬取_python爬取小说-CSDN博客

由笔者本人根据需求简化修改而来,原文并未使用正则表达式的方法

原文作者:Myster_KID

本文旨在传播Python爬虫知识,无任何收入,如有侵权请联系我删除

  • 48
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值