大家好,上次我们实验了爬取了糗事百科的段子,那么这次我们来尝试一下爬取百度贴吧的帖子。与上一篇不同的是,这次我们需要用到文件的相关操作。
本篇目标
对百度贴吧的任意帖子进行抓取
指定是否只抓取楼主发帖内容
将抓取到的内容分析并保存到文件
1. URL格式的确定
首先,我们先观察一下百度贴吧的任意一个帖子。
比如:http://tieba.baidu.com/p/3138733512?see_lz=1&pn=1
,这是一个关于NBA50大的盘点,分析一下这个地址。
http://
代表资源传输使用http协议
tieba.baidu.com
是百度的二级域名,指向百度贴吧的服务器。
/p/3138733512
是服务器某个资源,即这个帖子的地址定位符
see_lz
和pn
是该URL
的两个参数,分别代表了只看楼主和帖子页码,等于1表示该条件为真
所以我们可以把URL分为两部分,一部分为基础部分,一部分为参数部分。
例如,上面的URL我们划分基础部分是 http://tieba.baidu.com/p/3138733512
,参数部分是 ?see_lz=1&pn=1
2. 页面的抓取
熟悉了URL的格式,那就让我们用urllib2库来试着抓取页面内容吧。上一篇糗事百科我们最后改成了面向对象的编码方式,这次我们直接尝试一下,定义一个类名叫BDTB(百度贴吧),一个初始化方法,一个获取页面的方法。
其中,有些帖子我们想指定给程序是否要只看楼主,所以我们把只看楼主的参数初始化放在类的初始化上,即init方法。另外,获取页面的方法我们需要知道一个参数就是帖子页码,所以这个参数的指定我们放在该方法中。
综上,我们初步构建出基础代码如下:
1 | #-*-coding:utf8-*- |
运行代码,我们可以看到屏幕上打印出了这个帖子第一页楼主发言的所有内容,形式为HTML代码。
3. 提取相关信息
1)提取帖子标题
在浏览器中审查元素,或者按F12,查看页面源代码,我们找到标题所在的代码段如下:
1 | <h3 class="core_title_txt pull-left text-overflow " title="纯原创我心中的NBA2014-2015赛季现役50大" style="width: 416px">纯原创我心中的NBA2014-2015赛季现役50大</h3> |
所以我们要提取 <h3>
中的内容,因为一开始可以查看整个界面的原代码,查看里面含有 <h3>
标签的不止一个。所以需要写正则表达式来匹配,如下:
1 | <h3 class="core_title_txt.*?>(.*?)</h3> |
然后,我们可以写个获取标题的方法
1 | # 获取帖子标题 |
2)提取帖子页数
同样地,帖子总页数我们也可以通过分析页面中的共?页来获取。
1 | <li class="l_reply_num" style="margin-left:8px"><span class="red" style="margin-right:3px">4784</span>回复贴,共<span class="red">36</span>页</li> |
所以我们的获取总页数的方法如下
1 | #获取帖子一共有多少页 |
3)提取正文内容
审查元素,可以看到百度贴吧每一层楼的主要内容都在
标签里面,所以我们可以写如下的正则表达式1 | <div id="post_content_.*?>(.*?)</div> |
所以提取正文内容的方法:
1 | #获取每一层楼的内容,传入页面内容 |
运行截图如下:
可以看到有很多的换行符和图片符,既然出现这样的情况,那肯定不是我们想要的结果。那我们就必须要将文本进行处理,将各种复杂的标签给剔除,还原帖子的原来面貌。可以使用一个方法或者类将这个处理文本的实现,不过为了更好的代码重用和架构,还是建议使用一个类。
我们将这个类命名为Too
(工具类),里面定义一个replace
方法,替换各种标签。然后在类中定义几个正则表达式,利用re.sub
方法对文本进行匹配后然后替换。
1 | import re |
在使用时,我们只需要初始化一下这个类,然后调用replace方法即可。
现在整体代码是如下这样子的,现在我的代码是写到这样子的:
1 | #-*-coding:utf8-*- |
运行截图如下:
4)替换楼层
至于这个问题,我感觉直接提取楼层没什么必要呀,因为只看楼主的话,有些楼层的编号是间隔的,所以我们得到的楼层序号是不连续的,这样我们保存下来也没什么用。
所以可以尝试下面的方法:
1.每打印输出一段楼层,写入一行横线来间隔,或者换行符也好。
2.试着重新编一个楼层,按照顺序,设置一个变量,每打印出一个结果变量加一,打印出这个变量当做楼层。
将getContent
方法修改如下:
1 | #获取每一层楼的内容,传入页面内容 |
运行结果截图如下:
4. 写入文件
代码:
1 | file = open(“tb.txt”,”w”) |
5. 完善代码
1 | #-*-coding:utf8-*- |
运行后截图如下:
备注:
运行后注意输入帖子的代号先在网址后空格,再输入帖子代号,输入完再把刚才的空格
删除,只有这样才不会报错。
Traceback (most recent call last):
File “E:/python/code/PycharmProject/Python-Projects/baidutieba/BDTB3.py”, line 149,
in < module >
bdtb.start()
File “E:/python/code/PycharmProject/Python-Projects/baidutieba/BDTB3.py”, line 123, in start
pageNum = self.getPageNum(indexPage)
File “E:/python/code/PycharmProject/Python-Projects/baidutieba/BDTB3.py”, line 86, in getPageNum
result = re.search(pattern,page)
File “C:\Python27\lib\re.py”, line 146, in search
return _compile(pattern, flags).search(string)
TypeError: expected string or buffer