今天和大家分享的是python爬虫实战,由于本人最近迷上了看网络小说,学生党又穷,只能看看网络dao版小说,现在这类dao版小说网站可以说非常的多,但是所有的网站进去都可以看见一大把的广告信息,非常影响我们的阅读体验,所以我打算将dao版小说网站的小说内容通过学习到的python爬虫技术爬取下来搭建自己的小说网站,有了今天的这篇文章。
第一步,选取目标:
对于目标网站的选取,我们作为以为忠实的小说迷,自然要选择小说更新速度快并且访问稳定的小说网站(dao版)进行数据爬取。“笔趣阁”作为现代dao版小说网站的始祖,我们通过百度搜索相关关键词,找到了目前百度排行第一的“笔趣阁”网站,
小编我只看穿越类型的小说,所以只选取了穿越类型的小说进行爬取。在我看来,爬取数据最重要的是思路,首先我们要明确我们爬取的思路,还好这种小说类型的网站网络页面都是非常的标准荷统一化,我们的大体思路如下:
第二步:爬虫的编写
根据我们上面思路,我们需要用到以下模块:
Requests模块,用于发送网络请求
Lxml的etree模块,格式化我们的网页数据,便于我们使用xpath提取网页数据
Retrying模块,由于网络延迟会造成我们的数据请求失败,使用retrying模块来重新发送我们的网络请求
Tips:XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。Xpath教程:https://www.w3school.com.cn/xpath/index.asp,在百度上学习了一个小技巧,使用chrome浏览器的开发者功能,选取目标元素,在elements模块下面右键选中的模块可以直接将该元素的xpath地址复制出来。
1. 首先创建一个发送网络请求,返回标准网页数据的函数GetUrl,代码如下:
@retry(stop_max_attempt_number=5)def GetUrl(url): respose = requests.get(url, timeout=5) return etree.HTML(respose.content.decode())#定义一个获取URL内容,并且返回一个被lxml模块格式化标准网页数据
2. 定义我们的获取小说列表、小说章节以及章节内容的三个函数GetBookList,GetChapterList,GetContent代码如下:
def GetBookList(url): content = GetUrl(url) booklist = [] bookname = content.xpath("//*[@id='newscontent']/div[1]/ul/li[1]/span[1]/a/text()")[0] print("开始采集《{}》".format(bookname)) for book in content.xpath("//*[@id='newscontent']/div[1]/ul/li"): booklist.append(book.xpath("./span[1]/a/@href")[0]) return booklist#定义一个获取小说链接的函数def GetChapterList(url): content = GetUrl(url) chapterlist = [] for chapter in content.xpath("//*[@id='list']/dl/dd"): chapterlist.append("http://www.xbiquge.la" + chapter.xpath("./a/@href")[0]) return chapterlist#定义一个获取小说章节的函数def GetContent(url): temp = GetUrl(url) chaptername=temp.xpath("//*[@class='bookname']/h1/text()")[0] content = temp.xpath("//*[@id='content']/text()") str = "" for con in content: str = str + con.replace("\r", "") print(chaptername) return str#定义一个获取小说章节内容的函数
根据以上的思路,我们的所有代码如下图所示
以上代码没有写保存函数,大家可以根据自己的需求把采集下来的数据保存到文本文件或是数据库,我们一保存为txt文本为例:
with open('{}.txt'.format(i), 'wb') as f:f.write(content)
便可按照小说的章节序号保存
模块解析
(1) Requests模块:
1. 向网站发送请求:requests.get(url),requests.post(url),可以使用get和post方式向网站发送请求。如果用用post发送请求,则配置requests.post(url,data=post请求参数)的形式发送。
2. 可以自定义请求头信息,requests.get(url,headers=自定义请求头信息),可以自定义user-agent和cookie信息,来绕过网站的反爬手段。
3. 返回的响应正文不论什么类型,都可以用text获取。
(2) lxml模块
此次我们运用的是lxml模块当中的etree,etree.HTML()可以用来解析字符串格式的HTML文档对象,将传进去的字符串转变成_Element对象。作为_Element对象,可以方便的使用getparent()、remove()、xpath()等方法。
(3) Retrying模块
我们在写爬虫的过程中,经常遇到爬取失败的情况,这个时候我们一般会通过try块去进行重试,但是每次都写那么一堆try块,真的是太麻烦,所以我们用到retrying模块,被修饰的函数执行失败会自动重新执行。
stop_max_attempt_number:最大重试次数,超过这个次数会停止重试,并报异常。
wait_random_min:随机等待最小时间。
wait_random_max:随机等待最大时间。
第三,软件的实际运行:
爬虫运行效果截图
本来可以一直开着我们的脚本在后台运行,但是运行一会儿我们发现脚本就报错停止了,研究了一番我们才发现由于对方访问有IP过滤的反爬措施,所以这里我们需要将我们的爬虫加入自动切换代理IP的功能。我们的requests模块支持代理功能,在网上找找几个代理,按照如下方式加入我们的代理到爬虫代码当中:
proxy_dict = { "http": "http://username:password@hogehoge.proxy.jp:8080/", "https": "http://username:password@hogehoge.proxy.jp:8080/"}#引入我们爬虫程序需要使用的模块@retry(stop_max_attempt_number=5)def GetUrl(url): respose = requests.get(url, timeout=5,proxies=proxy_dict) return etree.HTML(respose.content.decode())
至此我们的小说爬虫便可以一直在电脑上运行了,今天的分享也到此结束,由于是爬虫新手,文章中有错误的地方也希望大家指出和谅解,谢谢大家。
本期作者:汪苏彬