完全小白篇 | 您所在的位置:网站首页 › python爬取txt文件 › 完全小白篇 |
完全小白篇-使用Python爬取网络小说
一、找一个你要爬取的小说二、分析网页网页的展示方式需要用到的库文件
三、向网站发送请求四、正则提取五、跳转的逻辑六、后续处理七、保存信息进入docx文件八、新的问题:超时重传
一、找一个你要爬取的小说
作为python小白,这篇博客仅作为我的一个学习记录。 本篇我就拿一个实际案例来做吧,短短50行代码调试了一晚上,爬虫还得继续好好学啊!拿最近很火的《元龙》举例。 (采用读书网的资源) 二、分析网页打开最开始的那章,按F12看一下网页代码,首先需要注意的地方无外乎两点: 从目录的网址后面添加了一个什么编号这个网站的网页编码格式是什么(在head标签里都能找到)各个章节之间具有怎样的跳转关系 跳转关系这一块,现在的小说网站已经不是按照章节+1编号也+1的方式了,所以我们可以考虑利用 a 标签里的 href="" 直接跳转我们要提取的信息有着怎样的风格 在下图中我们可以看到,每章标题、正文等我们要爬取的东西全部在p标签中![]() ![]() 在开始之前,先简单介绍一下这次使用到的库文件: from bs4 import BeautifulSoup #网页解析,数据获取 from docx import Document #操作Word的.docx文档 import re #正则表达式,文字匹配 import requests #根据指定url获取网页数据 from requests.adapters import HTTPAdapter #设置重传时有用 import os #最后用来暂停一下emm,如果有的苦还没有安装,那就pip就好了。 在任何一处cmd窗口下输入: pip3 install Beautifulsoup4 pip3 install docx pip3 install re pip3 install requests 三、向网站发送请求接下来我们开始一步步完善我们的思路: def main(): #目录的网址 baseurl = input("请输入目录列表的那个网址(例如https://www.dusuu.com/ml/1033/)\n") number = input("请打开该小说第一章,输入一下网址新增加的那个数字(例如2688178)\n") #试手,先开一下第一章试试 url = baseurl+str(number)+".html" #模拟浏览器身份头向对方发送消息,不过一般的小说网站没什么反爬机制,头的话可有可无 head = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"} print("已完成爬取的章节:") req = requests.get(url = url, headers = head) #上文我们已经看到是UTF-8的编码格式,这里照搬按此解析即可 req.encoding = 'UTF-8' #解析得到网站的信息 soup = BeautifulSoup(req.text, 'html.parser') print(soup) os.system("pause") if __name__ == "__main__": main()
这里就要使用bs4库中的搜索函数find_all(),以及re库中的提取函数.findall() 我们首先搜索所有必要的item: for item in soup.find_all('div',class_="bookname"): item = str(item) title = re.findall(findTitle, item)[0] for item in soup.find_all('div',id="content"): item = str(item) end = re.findall(findEnd, item)我们定义一下提取的方式: #创建正则表达式对象,r是为了避免对'/'的错误解析 findTitle = re.compile(r'(.*?)',re.S) findEnd = re.compile(r'(.*?) ',re.S)这样,便可以将标题和正文的内容全部提取出来了 五、跳转的逻辑现在我们完全可以处理一个网页的信息了,那么如何跳转到别的章节呢? 利用a标签“下一章”的跳转链接即可 同样,还是 for item in soup.find_all('a',id="pager_next"): item = str(item) link = re.findall(findLink, item)[0] url = "https://www.dusuu.com" + str(link)正则对象(规则)为: findLink = re.compile(r'下一章') 六、后续处理现在的代码段为: from bs4 import BeautifulSoup #网页解析,数据获取 from docx import Document #操作Word的.docx文档 import re #正则表达式,文字匹配 import requests #根据指定url获取网页数据 from requests.adapters import HTTPAdapter #设置重传时有用 import os #最后用来暂停一下 findTitle = re.compile(r'(.*?)',re.S) findEnd = re.compile(r'(.*?) ',re.S) findLink = re.compile(r'下一章') def main(): baseurl = input("请输入目录列表的那个网址(例如https://www.dusuu.com/ml/1033/)\n") number = input("请打开该小说第一章,输入一下网址新增加的那个数字(例如2688178)\n") url = baseurl+str(number)+".html" link = "" head = { #模拟浏览器身份头向对方发送消息 "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" } print("已完成爬取的章节:") #最后一章中,点击“下一章”会回到目录那里 while(link!="/ml/10942/"): req = requests.get(url = url, headers = head) req.encoding = 'UTF-8' soup = BeautifulSoup(req.text, 'html.parser') for item in soup.find_all('div',class_="bookname"): item = str(item) title = re.findall(findTitle, item)[0] print(title) for item in soup.find_all('div',id="content"): item = str(item) end = re.findall(findEnd, item) #每章最后一句正文都是网站的广告,我们不要那个 for i in range(len(end)): if(i==(len(end)-1)): end[i]="\n" print(end) #跳转到下一页 for item in soup.find_all('a',id="pager_next"): item = str(item) link = re.findall(findLink, item)[0] url = "https://www.dusuu.com" + str(link) os.system("pause") if __name__ == "__main__": main()
其实每获得一次title,每获得一次end,就完全可以对一个docx文档进行写标题、写段落操作了 这里提示几个操作的docx文档的必要语法: 库函数:from docx import Document创建一个文档对象:Doc = Document()写标题操作:Doc.add_heading(title, level = 0) 注意,level从0到5是一级标题–>六级标题写段落操作:Doc.add_paragraph() 八、新的问题:超时重传在完成一系列操作后,我在运行时,前几章是完全没有问题的。然而,随着章节增加以及访问次数的增加,出现了一个新的问题:访问无限超时。可能是每个小说网站都存在这个问题,连续高频访问可能就会在某次访问突然“掉线” 查了很多方法,在这里总结一下各个比较通用的方法以及效果: 全局设置Socket超时时长: 在全局设置: import socket socket.setdefaulttimeout(time_len)但是确实,效果不明显,当章节多了仍然会无限超时 设置DNS 比如,将本地的DNS优先设置为阿里的,或者腾讯、百度的公用DNS,效果是有的,但事实上是超时的出现减少了,当超时出现时仍然无法得到解决 超时重传 有点综合以上两种方法。查了很多,但是可能是需要一定基础的,诸如retry()等。 这里我采用了最基础的try: 首先增加一个库:from requests.adapters import HTTPAdapter 在我们的函数中,req这个变量进行一些新的设置: req=requests.Session() #访问https协议时,设置重传请求最多3次 req.mount('https://',HTTPAdapter(max_retries=3))另外,对于req设置超时时长: #5s的超时时长设置 req = requests.get(url = url, headers = head, timeout=5)如果超时,打印错误: except requests.exceptions.RequestException as e: print(e)总代码如下: from bs4 import BeautifulSoup #网页解析,数据获取 from docx import Document import os import re #正则表达式,文字匹配 import requests from requests.adapters import HTTPAdapter findTitle = re.compile(r'(.*?)',re.S) findEnd = re.compile(r'(.*?) ',re.S) findLink = re.compile(r'下一章') def main(): baseurl = input("请输入目录列表的那个网址(例如https://www.dusuu.com/ml/1033/)\n") # https://www.dusuu.com/ml/10942/ Doc = Document() number = input("请打开该小说第一章,输入一下网址新增加的那个数字(例如2688178)\n") #2622647 savepath = "./"+input("请为你的docx文档命名:")+".docx" url = baseurl+str(number)+".html" link = "" req=requests.Session() req.mount('https://',HTTPAdapter(max_retries=3)) head = { #模拟浏览器身份头向对方发送消息 "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36" } print("已完成爬取的章节:") while(link!="/ml/10942/"): try: req = requests.get(url = url, headers = head, timeout=5) req.encoding = 'UTF-8' soup = BeautifulSoup(req.text, 'html.parser') for item in soup.find_all('div',class_="bookname"): item = str(item) title = re.findall(findTitle, item)[0] print(title) Doc.add_heading(title, level = 0) for item in soup.find_all('div',id="content"): item = str(item) end = re.findall(findEnd, item) for i in range(len(end)): if(i==(len(end)-1)): end[i]="\n" Doc.add_paragraph(end[i]) Doc.save(savepath) #跳转到下一页 for item in soup.find_all('a',id="pager_next"): item = str(item) link = re.findall(findLink, item)[0] url = "https://www.dusuu.com" + str(link) except requests.exceptions.RequestException as e: print(e) os.system("pause") if __name__ == "__main__": main()好吧,免费获得了一个4.5MB的.docx文档,以后不用再上网看这部小说了! 当然,针对这个程序的话,读书网的所有小说都可以爬了。 (其实我还是得上网看,800多章还是直接用目录跳转方便) 不过,学习为主,又获得一项用50行代码在别人面前秀一秀的技能。 |
CopyRight 2018-2019 实验室设备网 版权所有 |