Python抓取百度贴吧网页信息以及代码下载

代码是抓取百度贴吧帖子的回复内容的。包括帖子标题、帖子回复数量,帖子页码,回复楼层、回复时间,也可以只查看楼主的回复信息。最后将获取到的帖子信息记录到记事本中。
具体结果看图:
这里写图片描述
上面的图片打印的是帖子的回复总数140,总共5页。这5页信息是只有楼主的回复,没有包含全部的回复。帖子标题。第一页数量30个回复,下面依次打印每一楼的回复信息,每楼层之间用*号隔开。

这里写图片描述
这个记事本保存的是楼主的回复内容,包括每次回复的楼层。

这里写图片描述
这是保存的记事本文档信息截图

这里写图片描述
这是全部回复,包括不是楼主的回复内容

这里写图片描述
控制台打印的最后一楼信息。

这里写图片描述
最后一楼回复的网页截图信息。

第一步:获取帖子html代码内容

#获取页面html文本内容
    def getPageContent(self,url):
        request = urllib2.Request(url)
        response = urllib2.urlopen(request)
        return response.read().decode('UTF-8')

在这里需要指定解码格式,具体的html文本解码格式,需要具体查看html页面的格式。如下图:
这里写图片描述

第二步:获取帖子标题和帖子回复总数、页码
这里写图片描述
箭头指向分别指向了三个信息。正则表达式如下:

#获取帖子标题
    def decodeTieziTitle(self,pagecontent):
        pattern = re.compile('<h\d.*?class="core_title_txt.*?>(.*?)</h\d>',re.S)
        title = re.findall(pattern, pagecontent)
        return title[0]
#获取页面回复数量和总页码
    def decodePageContentNum(self,pagecontent):
        patten = re.compile('<li class="l_reply_num".*?<span class="red".*?>(.*?)'+
                            '</span>.*?<span class="red".*?>(.*?)</span>',re.S)
        num =re.search(patten, pagecontent);
        return num
num = self.decodePageContentNum(pagecontent)
        print num.group(1),u'回复贴,共',num.group(2),u'页'

通过返回num值,group()方法来获取页码和回复帖子数量

第四步:解析文档内容,获取有用信息

#获取四个信息,用户名,内容,楼层,时间
    def decodePageContent(self,pagecontent):
        #获取四个信息,用户名d,内容,(),楼层,时间
#         pattern = re.compile('<div.class="d_author">.*?<ul class="p_author">.*?'+
#                              '<li class="d_name.*?<a.*?target="_blank">(.*?)</a>.*?'+
#                              '<div class="d_post_content_main.*?<div class="p_content ".*?<cc>.*?'+
#                              '<div.*?class="d_post_content j_d_post_content.*?>(.*?)'+
#                               '</div>.*?</cc>.*?'+
#                              '<div class="core_reply j_lzl_wrapper">.*?'+
#                              '<div class="core_reply_tail clearfix">.*?'+
#                              '<div class="post-tail-wrap">.*?<span class="j_jb_ele">.*?</span>'+
#                              '(.*?)'+
#                              '<span class="tail-info">(.*?)'+'[\u697c]'+'</span>.*?'+
#                              '<span class="tail-info">(.*?)</span>.*?</div>.*?'+
#                              '<ul class="p_props_tail props_appraise_wrap"></ul>',re.S)
        pattern = re.compile('<div.class="d_author">.*?<ul class="p_author">.*?'+
                             '<li class="d_name.*?<a.*?target="_blank">(.*?)</a>.*?'+
                             '<div class="d_post_content_main.*?<div class="p_content'+
                             ' ".*?<cc>.*?'+
                             '<div.*?class="d_post_content j_d_post_content.*?>(.*?)'+
                             '</div>.*?</cc>.*?'+
                             '<div class="core_reply j_lzl_wrapper">.*?'+
                             '<div class="core_reply_tail clearfix">.*?'+
                             '<div class="post-tail-wrap">'+
                             '(.*?)</div>',re.S)
#         pattern = re.compile('<div class="d_author">.*?<ul class="p_author">.*?'+
#                              '<li class="d_name".*?<a.*?'+
#                              'target="_blank">(.*?)</a>',re.S)
#         pattern = re.compile('<li class="d_name" data-field=".*?<a data-field=".*?'+
#                              'target="_blank">(.*?)</a>.*?</li>',re.S)
#         pattern = re.compile('<div class="d_author">(.*?)</div>',re.S)
        content = re.findall(pattern, pagecontent)
        print "len=",len(content)
        ls = []
        tail2 = re.compile('<span class="tail-info">(.*?)</span>.*?'+
                           '<span class="tail-info">(.*?)</span>', re.S)
        tail3 = re.compile('<span class="tail-info">.*?</span>.*?'+
                           '<span class="tail-info">(.*?)</span>.*?'+
                           '<span class="tail-info">(.*?)</span>',re.S)
        import sys;reload(sys);sys.setdefaultencoding('utf8');
        for item in content:
            n = re.subn('tail-info', 'tail', item[2])
            if n[1]==4:
                group3 = re.search(tail3, item[2])
                ls.append((item[0],item[1],group3.group(1),group3.group(2)))
            elif n[1]==3:
                group2 = re.search(tail2, item[2])
                ls.append((item[0],item[1],group2.group(1),group2.group(2)))
            else:
                print 'n error n=',n[1],'=='+item[2].decode('utf-8')
        return ls

这里的正则表达式比较长,需要根据具体的html代码进行调整。我想说的是,大家在写正则表达式的时候,一点点的测试,不要一下子就写很长的正则表达式,一次是写不对的,保证一点点的扩展,慢慢的增加内容,不断缩小获取信息的范围。
值的一提的是,上面的例子中,在获取楼层,时间信息的时候,有点麻烦,原因在有些楼层的回复是手机端回复的,html代码中是这样的:
这里写图片描述
就会有三个tail-info的span节点,如果是电脑端回复的帖子,就没有第一个节点span,只有后面两个span节点,并且,tail-info节点不止这三个,如图:
这里写图片描述

对于这种情况,无法再正则表达式中进行匹配,所以,我把中间的信息使用(.*?)获取到,之后替换tail-info字符串,如果替换的次数有四次,说明是客户端app发的帖子,直接取后面两个span节点信息。如果替换次数是三次,说明是电脑端发的帖子。分别使用正则表达式进行匹配获取信息。

tail2 = re.compile('<span class="tail-info">(.*?)</span>.*?'+
                           '<span class="tail-info">(.*?)</span>', re.S)
        tail3 = re.compile('<span class="tail-info">.*?</span>.*?'+
                           '<span class="tail-info">(.*?)</span>.*?'+
                           '<span class="tail-info">(.*?)</span>',re.S)
        import sys;reload(sys);sys.setdefaultencoding('utf8');
        for item in content:
            n = re.subn('tail-info', 'tail', item[2])
            if n[1]==4:
                group3 = re.search(tail3, item[2])
                ls.append((item[0],item[1],group3.group(1),group3.group(2)))
            elif n[1]==3:
                group2 = re.search(tail2, item[2])
                ls.append((item[0],item[1],group2.group(1),group2.group(2)))
            else:
                print 'n error n=',n[1],'=='+item[2].decode('utf-8')

这就是代码中的逻辑部分。

完成了这部分内容之后,最后一步,就是循环页码,获取每页帖子回复的信息记录到记事本中:

for i in range(int(self.pagenum)+1):#range函数不包括最大的值
            pagecontent = self.getPageContent(\
                self.baseUrl+urlid+self.seellz+str(see_lz)+self.urlpn+str(i))
            content = self.decodePageContent(pagecontent)
            picpattern = re.compile('<img class="BDE_Image" src="(.*?)".*?',re.S)
            #获取四个信息,用户名,内容,楼层,时间
            for con in content:
                print '*'*20
                strcon = '*'*20+os.linesep
                print u'楼层:',con[2]
                strcon += '楼层:'+con[2].encode('utf-8')+os.linesep
                print u'时间:',con[3]
                strcon += '时间:'+con[3].encode('utf-8')+os.linesep
                print u'用户名字:',con[0]
                strcon += '用户名字:'+con[0].encode('utf-8')+os.linesep
                li = re.findall(picpattern, con[1])
                if li is not None:
                    for l in li:
                        print u'内容图片:',l
                        strcon += '内容图片:'+l.encode('utf-8')+os.linesep
                print u'内容:',self.tool.replace(con[1])
                strcon += '内容:'+self.tool.replace(con[1]).encode('utf-8')+os.linesep
                self.writeTxt(strcon+os.linesep,f)
#帖子的每一个回复内容写入文件中
def writeTxt(self,strs,f):
        f.writelines(strs)

之后给出整个代码如下:

#_*_encoding=utf8_*_
'''
Created on 2015年11月22日

@author: 15361
'''
import urllib2
import re
import os
from scr.tool import Tool

class BDTB:
    def __init__(self):
#       'http://tieba.baidu.com/p/3138733512?see_lz=1&pn=1'  百度贴吧URL地址
        self.baseUrl = 'http://tieba.baidu.com/p/'
        self.seellz = '?see_lz=' #=1只看楼主 =0查看全部
        self.urlpn = '&pn=' #代表页码
        self.tool =Tool()

    #帖子的每一个回复内容写入文件中
    def writeTxt(self,strs,f):
        f.writelines(strs)

    #获取四个信息,用户名,内容,楼层,时间
    def decodePageContent(self,pagecontent):
        #获取四个信息,用户名d,内容,(),楼层,时间
#         pattern = re.compile('<div.class="d_author">.*?<ul class="p_author">.*?'+
#                              '<li class="d_name.*?<a.*?target="_blank">(.*?)</a>.*?'+
#                              '<div class="d_post_content_main.*?<div class="p_content ".*?<cc>.*?'+
#                              '<div.*?class="d_post_content j_d_post_content.*?>(.*?)'+
#                               '</div>.*?</cc>.*?'+
#                              '<div class="core_reply j_lzl_wrapper">.*?'+
#                              '<div class="core_reply_tail clearfix">.*?'+
#                              '<div class="post-tail-wrap">.*?<span class="j_jb_ele">.*?</span>'+
#                              '(.*?)'+
#                              '<span class="tail-info">(.*?)'+'[\u697c]'+'</span>.*?'+
#                              '<span class="tail-info">(.*?)</span>.*?</div>.*?'+
#                              '<ul class="p_props_tail props_appraise_wrap"></ul>',re.S)
        pattern = re.compile('<div.class="d_author">.*?<ul class="p_author">.*?'+
                             '<li class="d_name.*?<a.*?target="_blank">(.*?)</a>.*?'+
                             '<div class="d_post_content_main.*?<div class="p_content'+
                             ' ".*?<cc>.*?'+
                             '<div.*?class="d_post_content j_d_post_content.*?>(.*?)'+
                             '</div>.*?</cc>.*?'+
                             '<div class="core_reply j_lzl_wrapper">.*?'+
                             '<div class="core_reply_tail clearfix">.*?'+
                             '<div class="post-tail-wrap">'+
                             '(.*?)</div>',re.S)
#         pattern = re.compile('<div class="d_author">.*?<ul class="p_author">.*?'+
#                              '<li class="d_name".*?<a.*?'+
#                              'target="_blank">(.*?)</a>',re.S)
#         pattern = re.compile('<li class="d_name" data-field=".*?<a data-field=".*?'+
#                              'target="_blank">(.*?)</a>.*?</li>',re.S)
#         pattern = re.compile('<div class="d_author">(.*?)</div>',re.S)
        content = re.findall(pattern, pagecontent)
        print "len=",len(content)
        ls = []
        tail2 = re.compile('<span class="tail-info">(.*?)</span>.*?'+
                           '<span class="tail-info">(.*?)</span>', re.S)
        tail3 = re.compile('<span class="tail-info">.*?</span>.*?'+
                           '<span class="tail-info">(.*?)</span>.*?'+
                           '<span class="tail-info">(.*?)</span>',re.S)
        import sys;reload(sys);sys.setdefaultencoding('utf8');
        for item in content:
            n = re.subn('tail-info', 'tail', item[2])
            if n[1]==4:
                group3 = re.search(tail3, item[2])
                ls.append((item[0],item[1],group3.group(1),group3.group(2)))
            elif n[1]==3:
                group2 = re.search(tail2, item[2])
                ls.append((item[0],item[1],group2.group(1),group2.group(2)))
            else:
                print 'n error n=',n[1],'=='+item[2].decode('utf-8')
        return ls
    #获取帖子标题
    def decodeTieziTitle(self,pagecontent):
        pattern = re.compile('<h\d.*?class="core_title_txt.*?>(.*?)</h\d>',re.S)
        title = re.findall(pattern, pagecontent)
        return title[0]
    #获取页面回复数量和总页码
    def decodePageContentNum(self,pagecontent):
        patten = re.compile('<li class="l_reply_num".*?<span class="red".*?>(.*?)'+
                            '</span>.*?<span class="red".*?>(.*?)</span>',re.S)
        num =re.search(patten, pagecontent);
        return num
    #获取页面html文本内容
    def getPageContent(self,url):
        request = urllib2.Request(url)
        response = urllib2.urlopen(request)
        return response.read().decode('UTF-8')
    def start(self):
        urlid = raw_input("输入贴吧帖子ID:").strip()
        see_lz = raw_input("是否只看楼主的帖子(是输入1,否输入0):")
        sss = self.baseUrl+urlid+self.seellz+str(see_lz)+self.urlpn+str(1)
#         sss = 'http://tieba.baidu.com/p/3138733512?see_lz=0&pn=1'
        print 'url=',sss
        pagecontent = self.getPageContent(\
                sss)
        num = self.decodePageContentNum(pagecontent)
        print num.group(1),u'回复贴,共',num.group(2),u'页'
        self.pagenum = num.group(2)  #保存页码数量
        self.title = self.decodeTieziTitle(pagecontent)
        import sys;reload(sys);sys.setdefaultencoding('utf8');
        if see_lz==1:
            f = open(self.title+'-楼主.txt'.encode('utf-8'),'w+')
        else:
            f = open(self.title+'-全部.txt'.encode('utf-8'),'w+')
        self.writeTxt(num.group(1)+' post number,'+num.group(2)+'page number'+os.linesep,f)
        print u'帖子标题:%s' %self.title

        for i in range(int(self.pagenum)+1):#range函数不包括最大的值
            pagecontent = self.getPageContent(\
                self.baseUrl+urlid+self.seellz+str(see_lz)+self.urlpn+str(i))
            content = self.decodePageContent(pagecontent)
            picpattern = re.compile('<img class="BDE_Image" src="(.*?)".*?',re.S)
            #获取四个信息,用户名,内容,楼层,时间
            for con in content:
                print '*'*20
                strcon = '*'*20+os.linesep
                print u'楼层:',con[2]
                strcon += '楼层:'+con[2].encode('utf-8')+os.linesep
                print u'时间:',con[3]
                strcon += '时间:'+con[3].encode('utf-8')+os.linesep
                print u'用户名字:',con[0]
                strcon += '用户名字:'+con[0].encode('utf-8')+os.linesep
                li = re.findall(picpattern, con[1])
                if li is not None:
                    for l in li:
                        print u'内容图片:',l
                        strcon += '内容图片:'+l.encode('utf-8')+os.linesep
                print u'内容:',self.tool.replace(con[1])
                strcon += '内容:'+self.tool.replace(con[1]).encode('utf-8')+os.linesep
                self.writeTxt(strcon+os.linesep,f)
bdtb = BDTB()
bdtb.start()

最后需要提一点的是,以上代码是对于
http://tieba.baidu.com/p/3138733512?see_lz=0&pn=1
该地址的帖子的信息的获取,其中3138733512代表帖子ID值。
see_lz代表是否只看楼主的回复帖子
该值=0 查看全部回复帖子
该值=1 只查看楼主回复帖子
pn 代表页码

对于该网址信息下的网页 信息,以上代码是正确的。对于别的帖子的内容,本人试了一下好像需要做调整才行。

下载完整代码的,请猛戳这里!

Github地址,在这里!
该github地址下,不仅仅有该博客的内容,还有淘宝淘女郎、糗事百科网页信息的抓取内容,欢迎关注!^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章