运行的环境:
win10 x64
安装了anaconda3,基于Python3环境运行
使用Pycharm编程
-
安装 requests模块,API参考
-
安装 BeautifulSoup 4.2模块,API参考
作为一个从事大数据小白,既然口口声声的说自己从事大数据,那么如果说自己不懂得怎么去收集数据,实在是有点说不过去。之前一直有过进行爬虫的相关经验,但是一直的没有对自己的知识进行一些整理,每次都是按照教程一步一步的设置,然后爬取数据。总的过程很是繁琐,也走了不少弯路。废话不多说😆。主要也是帮助我的「女朋友」完成论文所需要的文本素材。
直奔主题:本次主要是想收集小说网站,「武侠小说网」 http://www.wuxia.net.cn/author.html,中的关于武侠的所有文章。
网站的首页如下:
网站首页
我们使用chrome浏览器来分析其中的网络页面,“选中感兴趣的链接”→“右键检查”,弹出感兴趣的部分数据。
操作如图
使用谷歌浏览器,我们可以分析出我们需要爬取的主要两个步骤。
-
爬取「主页」中的所有作者链接,如第一张图片所示;
-
爬取作者页面下「所有文章」的文章链接;
-
爬取文章页面下的「所有文章章节」链接。
明确了思路之后,我们就依次实现这上面的实例。
我们明白了上面的思路,但我们该怎么一步一步的去实现,这个目的呢,就先就是如何利用Python进行单个网页的连接与解析。
如何使用request模块来获得网页的请求?这里有一个很重要的概念就是,在同一网站中,尽可能的使用同一个「session」。这样的目的可以很大节省我们“请求”→“服务器”之间请求的时间。具体代码操作如下。
查看request模块中,session.get方法的解释
解释图片
就是,我们使用_get()_方法之后,会获得一个对象,也会设定了一个会话session。这个session,可以继续用于我们在同一个网站内的访问。如果后面继续解析url的时候,没有使用同一个session (直接就是),就会类似于认为每次重新打开浏览器,然后再输入链接,获取Response对象。而使用同一个session,就会认为是同一人在网站内直接内部跳转,这样可以加速解析url的速度。这也是每次我开始爬虫的时候,都会考虑设置一个「Session」对象。
1. 解析URL链接
如果你打印res的类型的话,就会发现是 。返回Response对象,res就是描述整个url网页链接内容的描述结构。打印属性,就会发现,和你直接在浏览器中查看源码所看到的内容是一样的。
2. 抛出链接解析的异常
当我们在链接大量的网页连接的时候,总是可能在执行的时候出现很多异常的情况,比如,链接超时,网页不存在等。导致网页异常,但是我们程序在运行的时候,通常都不会报告这种异常。我通常会在代码中加入 ,用来手动抛出异常。如果解析出现问题的话。
3. 正确的编码格式
不同网站的内容往往经过不同的编码,就算同一个网站,不同网页之间也存在使用不同编码的情况。如果不能够很好的处理网页编码的内容,那么很容易就得不到我们想要的结果。在解析的Response对象中,往往也会告诉我们该网站使用了何种编码格式。具体实现代码如下:
上面中,是Response对象的res的属性,是自己指定的类型,我通常指定为“GBK”。
4. 使用合适的解析器来解析html文档
对于[上面](#3. 正确的编码格式) 得到的,就是我们通常接触到的网页标准格式,有四种不同的解析器来解析html,它们在解析速度和方法上对后面即将介绍的查找方法,有一定程度的影响。就是不同解析器解释出来的对象,使用同样的,“选择器”,“过滤器”可能会得出不一样的结论。如果有兴趣查看4种不同解析器的影响,可以BeautifulSoup 官方文档 安装解析器。我们选用通用性、解析速度都较优的“lxml" 。
这样才真正的获得了一个BeautifulSoup对象。该对象,详细的解释了整个html的结构。
5. 如果获得自己感兴趣的那部分内容
上面4得到的对象,是完整的描述了整个网页内容,但是我们通常只需要获取其中我们感兴趣的一部分。这就要开始详细介绍中的「爬虫利器」,“选择器”select()方法。通过CSS的内容来选中自己需要的信息。
具体的可以参考官网教程:
用select()方法寻找元素,用法介绍 ,“选择器的内容”及可匹配的含义表示如下
-
: 匹配所有名为 的元素
-
:匹配所有id属性为author的元素
-
:匹配使用CSS中class属性名为notice的元素
-
所有在元素内的 元素
-
:所有在元素之内的元素,中间没有其它的元素
-
:所有名为,并有一个name属性,其值无所谓的元素
-
:所有名为,并有一个type属性,其值为button的元素
上面只是列举一些常用的CSS选择器的模式,其他的可以参考别的资料。返回的是一个tag对象列表
6. 小结
通过上面的分析,我们可以将它们包装组合到一起,让我们下次,只需要输入「url」和「解析规则」,就可以只返回我们感兴趣的内容。具体代码如下:
通过上面的分析,我们就应该清晰的知道,需要通过「主页链接」来获得所有的作者链接信息。我们需要两个重要的信息,一个就是主页链接,这个很容易获取,就是“http://www.wuxia.net.cn/author.html”;另一个就是「解析规则」。解析规则可以借助Chrome中的F12工具获取,具体的操作如下。
复制解析规则
选中,“检查”→“Copy”→“Copy Selector”,这个是时候可以看到,复制出来的内容为
语法需要参考CSS教程,这里不多说。但是如果你直接将这个复制到 bsObj.select(“”)中,你猜你会看到啥?
得到的结果,往往会是None。我个人也并不是很理解,很多情况我自己也是不断的在尝试,我个人认为可能是由于不同的解析器规则原因,因为解析的标准和实际CSS选择的标准不一样。如果你有更好的方法,欢迎留言告知。
所以这时候我通常会选择性的删除部分内容。将「解析规则」简化。比如,使用 解析规则,就可以将所有的网页a标签解析出来。
1. 解释下 BeautifulSoup中的 标签
标签在网页爬取中,太常见啦,因为你通常都是从一个链接中获得一个链接再扩散到其它链接。如何获取 标签中所需要的内容?具体的一个 标签内容如下:
我们通常需要获取 中的链接,“/author/baiyu.html”,还有 里面的内容,“白羽”。其中 , 是 标签的属性,而“白羽” 标签的值。获取方式分别为:
不管是 标签还是其它的html标签,获取属性和值得方式是一样的。
明白了这个,就可以批量的获取所有「作者页面」的所有「作者主页」链接。
2. 分析作者页面部分的源码
通过首页的部分源码,我们分析出,主要包含了两种我们感兴趣的内容,「authorUrl」和「作者名」,经过分析,主要有如两种内容格式:
一种是作者在下的内容中,一种是还包含了标签来修饰,对于这种我们需要分别处理。对于上面获取的链接,通过如下的代码,把所有的的「authorUrl」和「作者名」保存下来。
通常对于这类明显的包含了格式话的数据,后期可以考虑包装成一个类,不然每次序列化和反序列化还需要写出名称,很容易出错。
3. 保存整个list内容
序列化可以通过很多的方式,这个都可以参考很多序列化的内容,比如pickle,ppprint模块等,也可以参考廖雪峰的官网。但是我这里比较喜欢这届序列化为文本形式的json字符串形式,因为阅读性和可修改性非常的好。主要就是因为我自己并不是需要非常的注重性能。
这里我主要写下两个函数,分别用于方便的「读取」和「保存」我们得到的列表变量数据。
- 保存列表的变量
- 读取列表中的变量值
我们在上面的程序中运行代码,将会在相对路径下生成如下文件名的文件。
我这样费劲心机的序列化的主要原因就在于,方便后续的过程中能够直接从文件中读取数据变量。而不是每次都爬取一遍地址数据,同时可以在文本编辑器中直接的进行修改。因为「程序不是万能的」,也是偶尔可以直接通过文本修改。
加载文件,使用方法如下:
4. 解决网页爬取过程中的相对url路径问题
很多时候我记得网上有一个叫urlparse的模块,专门处理这部分的逻辑,但是我这里就没有,直接使用自己写下的一个函数,简单粗暴的进行合并。
5. 小结
下面是基于上面分析的内容,写出的第一次爬取所有的作者链接的代码。
解析的主页内容。这里读取第二个作者的连接进行分析。
解析的主页内容
这里我们可以借鉴上面的思路,将获取的链接一样的存入文件。
整体之间的代码如下:
得到的json结果如下:
我们同样的选取所有内容。网站链接。分析网页的源码如下
根据文章的链接发现,文章的「文章名」在标签 下,「章节名」在标签 标签中。
现在解析内容和前面的核心思想相差无几,就不过多的介绍啦,直接上代码。
常用的一些操作
- 打开浏览器”
- 使用程序模拟打开一个网页链接的操作
注意事项
- 当编码格式出错是,可以使用 来修改读入的编码格式
过滤器
实际的爬虫过程中,常用的函数有findAll方法,该方法非常的好用,重点介绍。
先介绍一下过滤器的类,这些过滤器贯穿整个搜索的API.过滤器可以被用在tag的name中,节点的属性中,字符串中或他们的混合中.
-
字符串:例如,查找文档中所有的标签:
-
正则表达式:通过正则表达式的 来匹配内容。下面例子中找出所有以开头的标签,这表示和标签都应该被找到:
-
列表:会返回列表中任一元素匹配的内容。找到文档中所有标签和标签:
-
True:True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
- 方法: 方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False。下面方法校验了当前元素,如果包含 class 属性却不包含 id 属性,那么将返回 True。
- 使用lambda表达式:也是方法的定义一种,唯一的限制条件必须把函数的标签作为参数且返回结果是布尔类型,例如,返回有两个属性的标签
2. find_all()
非常好用的 。find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.
Google API
-
控制台页面 https://console.developers.google.com 开启和关闭API
-
产品页面 https://developers.google.com/products
爬虫过程中编码问题
如果清楚的直到是那种编码格式,那就直接使用,如果不清楚,可以使用 来自动检测
关于Python技术储备
Python越来越火了,离全民学Python的时代不远了,python应用场景那么多,不管是做主业还是副业或者别的都行,技多不压身,我这里有一份全套的 Python 学习资料,希望给那些想学习 Python 的小伙伴们一点帮助!