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地址下,不僅僅有該博客的內容,還有淘寶淘女郎、糗事百科網頁信息的抓取內容,歡迎關注!^_^

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