python爬虫实战二之爬取百度贴吧帖子
来源:互联网 发布:网络机顶盒能收多少台 编辑:程序博客网 时间:2024/06/05 04:55
目标:
1.对百度贴吧的任意帖子进行抓取
2.指定是否只抓取楼主发帖内容
3.将抓取到的内容分析并保存到文件
1.URL格式的确定
首先,我们先观察一下百度贴吧的任意一个帖子。比如:http://tieba.baidu.com/p/3138733512?see_lz=1&pn=1,分析一下地址
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方法。另外,获取页面的方法我们需要知道一个参数就是帖子页码,所以这个参数的指定我们放在该方法中。
综上,我们初步构建出基础代码如下:
import urllib.requestfrom urllib.request import urlopenimport urllib.errorimport re#百度贴吧爬虫类class BDTB:#初始化,传入基地址,是否只看楼主的参数 def __init__(self,baseurl,seeLZ): self.baseURL=baseurl self.seeLZ='?see_lz='+str(seeLZ) #传入页码,获取该页帖子的代码 def getPage(self,pageNum): try: url=self.baseURL+self.seeLZ+'&pn'+str(pageNum) request=urllib.request.Request(url) response=urllib.request.urlopen(request) print(response.read().decode('utf-8')) return response except urllib.error.URLError as e: if hasattr(e,'reason'): print(u'连接百度贴吧失败,错误原因',e.reason) return NonebaseURL='http://tieba.baidu.com/p/3138733512'bdtb=BDTB(baseURL,1)bdtb.getPage(1)部分运行结果:(可以看到屏幕上打印出了这个帖子第一页楼主发言的所有内容,形式为HTML代码)
<a data-field='{"un":"\u660e\u4e4b\u7ffc"}'alog-group="p_author" class="p_author_name j_user_card" href="/home/main?un=%E6%98%8E%E4%B9%8B%E7%BF%BC&ie=utf-8&fr=pb" target="_blank">明之翼</a>
</li>
<li class="l_badge" style="display:block;">
<div class="p_badge">
<a href="/f/like/level?kw=nba&ie=utf-8&lv_t=lv_nav_intro" target="_blank" class="user_badge d_badge_bright d_badge_icon3_1" title="本吧头衔12级,经验值6206,点击进入等级头衔说明页"><div class="d_badge_title ">MVP</div><div class="d_badge_lv">12</div></a>
</div>
3.提取相关信息
1)提取帖子标题
关于标题的源代码:<h3 class="core_title_txt pull-left text-overflow" title="纯原创我心中的NBA2014-2015赛季现役50大" style="width: 396px">纯原创我心中的NBA2014-2015赛季现役50大</h3>
所以我们想提取<h3>标签中的内容,同时还要指定这个class唯一,因为h3标签实在太多,正则表达式如下
<h3 class="core_title_txt .*?>(.*?)</h3>
所以我们增加一个获取标题的方法
def getTitle(self): page=self.getPage(1) pattern=re.compile('<h3 class="core_title_txt .*?>(.*?)</h3>',re.S) result=re.search(pattern,page) if result: #print result.group(1)#测试输出 return result.group(1).strip() else: return None
2)提取帖子页数
同样的,帖子总页数我们也可以通过分析页面中的?页来获取,所以我们的获取总页数的方法如下#获取帖子一共有多少页def getPageNum(self,page): pattern=re.compile('<li class="l_reply_num" .*?</span>.*?<span.*?>(.*?)</span>',re.S) result=re.search(pattern,page) if result: #print result.group(1)测试输出 return result.group(1).strip() else: return None
3)提取正文内容
def getContent(self,page): pattern=re.compile('<div id="post_content_.*?>(.*?)</div>',re.S) items=re.findall(pattern,page) for item in items: print(item)运行部分结果:
很多媒体都在每赛季之前给球员排个名,我也有这个癖好…………,我会尽量理性的分析球队地位,个人能力等因素,评出我心目中的下赛季50大现役球员,这个50大是指预估他本赛季在篮球场上对球队的影响力……不是过去的荣誉什么的,所以难免有一定的主观性……如果把你喜欢的球星排低了,欢迎理性讨论!<img class="BDE_Image" src="https://imgsa.baidu.com/forum/w%3D580/sign=557ae4d4fadcd100cd9cf829428947be/a9d6277f9e2f0708468564d9eb24b899a801f263.jpg" pic_ext="jpeg" pic_type="0" width="339" height="510"><br><br><br><br>状元维金斯镇楼<br>P.S 1 我每天都至少更新一个,不TJ。<br> 2 今年的新秀我就不考虑了,没上赛季参照
<img class="BDE_Image" src="https://imgsa.baidu.com/forum/w%3D580/sign=cb6ab1f8708b4710ce2ffdc4f3ccc3b2/06381f30e924b899d8ca30e16c061d950b7bf671.jpg" pic_ext="jpeg" pic_type="0" width="339" height="510"><br><br><br><br>50 惊喜新人王 <a href="http://jump2.bdimg.com/safecheck/index?url=x+Z5mMbGPAsY/M/Q/im9DR3tEqEFWbC4Yzg89xsWivS12AkS11WcjnMQsTddE2yXZInIi4k8KEu5449mWp1SxBADVCHPuUFSTGH+WZuV+ecUBG6CY6mAz/Zq1mzxbFxzAG+4Cm4FSU0=" class="ps_cb" target="_blank" onclick="$.stats.track(0, 'nlp_ps_word',{obj_name:'迈卡威'});$.stats.track('Pb_content_wordner','ps_callback_statics')">迈卡威</a><br>上赛季数据<br>篮板 6.2 助攻 6.3 抢断 1.9 盖帽 0.6 失误 3.5 犯规 3 得分 16.7<br><br><br>
可以看到,结果中还有一大片换行符和图片符,既然这样,我们就要对这些文本进行处理,把各种各样复杂标签给它剔除掉,还原精华内容,把文本处理写成一个方法也可以,不过为了实现更好的代码架构,我们可以考虑把标签等的处理写成一个类。
那就向他叫做tool(工具类),里面定义了一个方法,叫replace,是替换各种标签的,在类中定义了几个正则表达式,主要利用了re.sub方法对文本进行匹配后然后替换。具体的思路可以看注释。
import urllib.requestfrom urllib.request import urlopenimport urllib.errorimport re#处理页面标签类class Tool: #去除img标签,7位长空格 removeImg=re.compile('<img .*?>| {7}|') #删除超链接标签 removeAddr=re.compile('<a.*?>|</a>') #把换行的标签换为\n replaceLine=re.compile('<tr>|<div>|</div>|</p>') #将表格制表<td>替换为\t replaceTD=re.compile('<td>') #将段落开头换为\n加空两格 replacePara=re.compile('<p.*?>') #将换行符或双换行符替换为\n replaceBR=re.compile('<br><br>|<br>') #将其余标签剔除 removeExtraTag=re.compile('<.*?>') def replace(self,x): x=re.sub(self.removeImg,'',x) x=re.sub(self.removeAddr,'',x) x=re.sub(self.replaceLine,'\n',x) x=re.sub(self.replaceTD,'\t',x) x=re.sub(self.replacePara,'\n ',x) x=re.sub(self.replaceBR,'\n',x) x=re.sub(self.removeExtraTag,'',x) #strip()将前后多余的内容删除 return x.strip()# 百度贴吧爬虫类class BDTB:#初始化,传入基地址,是否只看楼主的参数 def __init__(self,baseurl,seeLZ): self.baseURL=baseurl self.seeLZ='?see_lz='+str(seeLZ) self.tool=Tool() #传入页码,获取该页帖子的代码 def getPage(self,pageNum): try: url=self.baseURL+self.seeLZ+'&pn'+str(pageNum) request=urllib.request.Request(url) response=urllib.request.urlopen(request) # print(response.read().decode('utf-8')) return response.read().decode('utf-8') except urllib.error.URLError as e: if hasattr(e,'reason'): print(u'连接百度贴吧失败,错误原因',e.reason) return None def getTitle(self): page=self.getPage(1) pattern=re.compile('<h3 class="core_title_txt .*?>(.*?)</h3>',re.S) #re.S整体匹配 result=re.search(pattern,page) if result: #print result.group(1)#测试输出 return result.group(1).strip() else: return None #获取帖子一共有多少页 def getPageNum(self,page): pattern=re.compile('<li class="l_reply_num" .*?</span>.*?<span.*?>(.*?)</span>',re.S) result=re.search(pattern,page) if result: #print result.group(1)测试输出 return result.group(1).strip() else: return None def getContent(self,page): pattern=re.compile('<div id="post_content_.*?>(.*?)</div>',re.S) items=re.findall(pattern,page) # for item in items: # print(item) print (self.tool.replace(items[1]))baseURL='http://tieba.baidu.com/p/3138733512'bdtb=BDTB(baseURL,1)bdtb.getContent(bdtb.getPage(1))Tool类看的不是特别懂,尤其是7位长空格是什么意思?做不到像原作者一样那么棒的匹配替换
部分运行结果如下:
50 惊喜新人王 迈卡威
上赛季数据
篮板 6.2 助攻 6.3 抢断 1.9 盖帽 0.6 失误 3.5 犯规 3 得分 16.7
新赛季第50位,我给上赛季的新人王迈卡威。 上赛季迈卡威在彻底重建的76人中迅速掌握了球队,一开始就三双搞定了热火赢得了万千眼球。后来也屡屡有经验的表现,新秀赛季就拿过三双的球员不多,迈卡威现在可以说在76人站稳了脚跟。
作为上赛季弱队的老大,迈卡威刷出了不错的数据,但我们静下心来看一看他,还是发现他有很多问题。
4)替换楼层
至于这个问题,我感觉直接提取楼层没什么必要呀,因为只看楼主的话,有些楼层的编号是间隔的,所以我们得到的楼层序号是不连续的,这样我们保存下来也没什么用。所以可以尝试下面的方法:
(1)每打印输出一段楼层,写入一行横线来间隔,或者换行符也好。
(2)试着重新编写一个楼层,按照顺序,设置一个变量吗,每打印出一个变量结果加一,打印出这个变量当做楼层
修改getContent方法如下:
def getContent(self,page): pattern=re.compile('<div id="post_content_.*?>(.*?)</div>',re.S) items=re.findall(pattern,page) floor=1 for item in items: print(floor,u'楼..................................................\n') print (self.tool.replace(item)) floor+=1部分运行结果:9 楼..................................................开更今天的了!10 楼..................................................47 神塔的绝唱 保罗加索尔上赛季数据篮板9.7 助攻3.4 抢断0.5 盖帽1.5 失误2.4 犯规2.1 得分17.4 作为上赛季湖人唯一一个明星级别的球员(以效率20左右看,科比也没达到)加索尔真心是尽力了,但是将要年满35岁的他还有多少油呢?就不得而知了!先来看看优点,作为NBA技术流内线的代表,加索尔策应,篮板,背筐,面框都是非常全能的表现,在进攻端,依然是内线做中轴的非常优秀的选择,防守端利用身高臂长,也能在禁区内有一定的威慑力。而且技术流的内线一般下滑比较慢,上赛季加索尔场均才13分本赛季恢复到了上上赛季的接近17+10的水平,不知道加索尔下一站还会不会是湖人,但是他依然可以用他自己的表现,帮助一支需要内线的球队发挥自身的能力。然后来看看问题所在,加索尔的命中率只有很一般的48%了,哥们你是内线啊!加索尔三分能力本来就不佳但受困于身体对抗能力的下降,加索尔的进攻离篮下越来越远,现在居然连续几个赛季开始丢三分了,但是28%的命中率就凄惨了。只要还在看湖人比赛的人就知道,加索尔现在的问题是身体机能下降,身体很多时候无法支持技术动作的完成,篮下终结力已经从顶级内线变成了一般内线,中距离也是逐年下滑,只是和一般的四号位球员差不多!遇到身体强硬的内线防守人几乎没有出手几乎,而且横移速度也在下滑,加之35岁的年龄,以及球队地位的不稳固(估计在哪一队都很难是当家球星了)我只能把他排在这个位置,不知道明年是否还能在50大之内呢?11 楼..................................................4.写入文件
最后便是写入文件的过程,过程很简单,就几句话的代码,主要是利用了以下两句:file = open(“tb.txt”,”w”)
file.writelines(obj)
5.完善代码
现在对代码进行优化重构,在一些地方添加必要的打印信息,整理如下:import urllib.requestfrom urllib.request import urlopenimport urllib.errorimport re#处理页面标签类class Tool: #去除img标签,7位长空格 removeImg=re.compile('<img .*?>| {7}|') #删除超链接标签 removeAddr=re.compile('<a.*?>|</a>') #把换行的标签换为\n replaceLine=re.compile('<tr>|<div>|</div>|</p>') #将表格制表<td>替换为\t replaceTD=re.compile('<td>') #将段落开头换为\n加空两格 replacePara=re.compile('<p.*?>') #将换行符或双换行符替换为\n replaceBR=re.compile('<br><br>|<br>') #将其余标签剔除 removeExtraTag=re.compile('<.*?>') def replace(self,x): x=re.sub(self.removeImg,'',x) x=re.sub(self.removeAddr,'',x) x=re.sub(self.replaceLine,'\n',x) x=re.sub(self.replaceTD,'\t',x) x=re.sub(self.replacePara,'\n ',x) x=re.sub(self.replaceBR,'\n',x) x=re.sub(self.removeExtraTag,'',x) #strip()将前后多余的内容删除 return x.strip()# 百度贴吧爬虫类class BDTB:#初始化,传入基地址,是否只看楼主的参数 def __init__(self,baseurl,seeLZ,floorTag): #base链接地址 self.baseURL=baseurl #是否只看楼主 self.seeLZ='?see_lz='+str(seeLZ) #HTML标签剔除工具类对象 self.tool=Tool() #全局file变量,文件写入操作对象 self.file=None #楼层标号,初始为1 self.floor=1 #默认标题,如果没有成功获取到标题的话则会用这个标题 self.defaultTitle=u'百度贴吧' #是否写入楼分隔符的标记 self.floorTag=floorTag #传入页码,获取该页帖子的代码 def getPage(self,pageNum): try: url=self.baseURL+self.seeLZ+'&pn'+str(pageNum) request=urllib.request.Request(url) response=urllib.request.urlopen(request) # print(response.read().decode('utf-8')) return response.read().decode('utf-8') except urllib.error.URLError as e: if hasattr(e,'reason'): print(u'连接百度贴吧失败,错误原因',e.reason) return None def getTitle(self,page): pattern=re.compile('<h3 class="core_title_txt .*?>(.*?)</h3>',re.S) #re.S整体匹配 result=re.search(pattern,page) if result: #print result.group(1)#测试输出 return result.group(1).strip() else: return None #获取帖子一共有多少页 def getPageNum(self,page): pattern=re.compile('<li class="l_reply_num" .*?</span>.*?<span.*?>(.*?)</span>',re.S) result=re.search(pattern,page) if result: #print result.group(1)测试输出 return result.group(1).strip() else: return None #获取每一楼层的内容 def getContent(self,page): pattern=re.compile('<div id="post_content_.*?>(.*?)</div>',re.S) items=re.findall(pattern,page) contents=[] for item in items: #将文本进行去除标签处理,同时在前后加入换行符 content='\n'+self.tool.replace(item)+'\n' contents.append(content.encode('utf-8')) return contents def setFileTitle(self,title): #如果标题不是为None,即成功获取到标题 if title is not None: self.file=open(title+'.txt','wb') else: self.file=open(self.defaultTitle+'.txt','wb') def writeData(self,contents): #向文件写入每一楼的信息 for item in contents: if self.floorTag=='1': #楼之间的分隔符 floorLine='\n'+str(self.floor)+u'.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................\n' self.file.write(floorLine.encode()) self.file.write(item) self.floor+=1 def start(self): indexPage=self.getPage(1) pageNum=self.getPageNum(indexPage) title=self.getTitle(indexPage) self.setFileTitle(title) if pageNum==None: print('URL已失效,请重试') return try: print('该帖子共有'+str(pageNum)+'页') for i in range(1,int(pageNum)+1): print('正在写入第'+str(i)+'页数据') page=self.getPage(i) contents=self.getContent(page) self.writeData(contents) #出现写入异常 except IOError as e: print('写入异常,原因'+e.message) finally: print('写入任务完成')print(u'请输入帖子代号')baseURL='http://tieba.baidu.com/p/'+str(input(u'http://tieba.baidu.com/p/'))seeLZ=input('是否只获取楼主发言,是输入1,否输入0\n')floorTag=input('是否写入楼层信息,是输入1,否输入0\n')bdtb=BDTB(baseURL,seeLZ,floorTag)bdtb.start()部分运行结果显示:1.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................AJ群星镇楼。2.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................几下拉杆来着?我数不清楚。3.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................酋长?假动作不错,不过我在天上等着你。4.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................其实90年代无防守,别喷我,我先承认这是我PS的好吗?5.......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................同样的进攻路线,你真不知道他到底会做什么。静觅 » Python爬虫实战四之抓取淘宝MM照片部分参考:
- Python爬虫实战之爬取百度贴吧帖子
- Python爬虫实战二之爬取百度贴吧帖子
- Python爬虫实战二之爬取百度贴吧帖子
- Python爬虫实战二之爬取百度贴吧帖子
- python爬虫实战二之爬取百度贴吧帖子
- [python3]爬虫实战二之爬取百度贴吧帖子
- Python爬虫实战:百度贴吧帖子
- python爬虫小项目: 爬取百度贴吧帖子
- python爬虫(13)爬取百度贴吧帖子
- python学习笔记之爬虫之爬取百度贴吧某一帖子
- Python爬虫实战二:下载百度贴吧帖子内的壁纸
- Python爬虫实战(2):百度贴吧帖子
- Python爬虫实战(2):百度贴吧帖子
- Python爬取百度贴吧帖子
- python 爬取百度贴吧 帖子
- python爬虫学习笔记2——百度贴吧帖子爬取
- [python爬虫]利用urllib2爬取百度贴吧帖子相关内容
- 简单的python爬虫程序(爬取百度贴吧帖子)
- 使用Post进行Http通信
- Python输出日志
- CSS自定义字体
- 博通机顶盒平台GPT分区和制作工具
- 发送短信内容过长时分多条发送
- python爬虫实战二之爬取百度贴吧帖子
- 二进制颜色代码大全附英文名(转载)
- 在APP中加载网页的套路(一):外壳的产生
- 【OpenCV学习笔记】二十五、轮廓查找与绘制(二)访问轮廓中每个点
- 人才留得住是因为本身就留得住 留不住的你永远留不住
- 设置条目字体大小
- guava——集合(2)
- 通俗易懂!超全面的移动端尺寸基础知识科普指南
- LR_函数