因剛剛開始學習python,水平有限,僅供參考,如果錯誤,歡迎大家在指出改正。 1.URL 地址分析
我選取的一個百度貼吧文章的網址是http://tieba.baidu.com/p/4739169817(這是一個秦時明月吧的文章,因小弟是秦迷),各位可以點擊進去查看一下。
如果點擊只看樓主或者翻頁,則會產生兩個參數http://tieba.baidu.com/p/4739169817?pn=2或http://tieba.baidu.com/p/4739169817?see_lz=1,分析一下該網址如下: http://tieba.baidu.com/p/4739169817?see_lz=1 這是網址 see_lz 該參數表示是否只看樓主發的文章,1表示true pn 該參數表示表示第幾頁 2.頁面抓取
我們構建一個類BDTB,該類作為爬取百度貼吧的主要的類,我們利用urllib包中的方法urlopen。
我選用的python版本為:python3.5,所以urllib包下又有四個包,分別為requeset、error…(詳情可查看官方文檔)
代碼如下:
import urllib.requestimport urllib.errorimport re#百度貼吧爬蟲類class BDTB: def __init__(self, baseUrl, seeLZ): self.baseURL = baseUrl self.seeLZ = '?see_LZ=' + str(seeLZ) self.tool = Tool() self.file = None self.defaultFileTitile = u'百度貼吧' self.floor = 1 def getPage(self, pageNum): try: url = self.baseURL + self.seeLZ + '&pn=' + str(pageNum) request = urllib.request.Request(url) response = urllib.request.urlopen(request) return response.read().decode('utf-8') except urllib.error.URLError as e: print('串連百度貼吧失敗,原因為:' + e.reason) return None
方法getPage()爬取頁面中的全部內容,參數pageNum為訪問的頁碼。 3.利用Regex提取需要的資訊 3.1 提取文章標題
我們可查看提取出的html檔案中的標題處的代碼,例如:
<h3 class="core_title_txt pull-left text-overflow " title="可能不是勝七弱,而是我們低估了骨妖梅三娘" style="width: 396px">可能不是勝七弱,而是我們低估了骨妖梅三娘</h3>
我寫的Regex為:
<h3 class="core_title_txt pull-left text-overflow.*?>(.*?)</h3>
因此代碼為:
#擷取文章標題 def getTitle(self): page = self.getPage(1) pattern = re.compile('<h3 class="core_title_txt pull-left text-overflow.*?>(.*?)</h3>', re.S) result = re.search(pattern, page) if result: return result.group(1) else: return None
3.2擷取文章總數
總起來說分析html代碼中的共幾頁的,然後書寫Regex。
#擷取文章一共有多少頁 def getPageNum(self): page = self.getPage(1) pattern = re.compile('<li class="l_reply_num.*?</span>.*?<span.*?>(.*?)</span>', re.S) result = re.search(pattern, page) if result: return result.group(1).strip() else: return None
3.3提取本文中的內容
核心問題是分析代碼主體中的想要提取的內容,根據具體的標籤分析出Regex,不多說,代碼如下:
#擷取每一層樓的內容 def getContent(self, page): pattern = re.compile('<div id="post_content_.*?>(.*?)</div>', re.S) result = re.findall(pattern, page) return result
大家還運行一下結果會發現,提取出來內容,裡面還有好多img\br等標籤,所以可以寫一個類或者方法,將其中的去除掉。代碼如下:
class Tool: removeTag = re.compile('<.*?>', re.I) def replace(self, x): x = re.sub(self.removeTag, '\n', x) return x.strip()
我寫的是一個類,很簡單,當然您也可以豐富起來。 3.4將爬下來的內容寫入檔案中
代碼很簡單,大家都會寫:
file = open(“tb.txt”,”w”) file.writelines(obj)
4.全部代碼
全部代碼,未經整理,最佳化,僅供參考:
#爬取百度貼吧中的文章的內容import urllib.requestimport urllib.errorimport reclass Tool: removeTag = re.compile('<.*?>', re.I) def replace(self, x): x = re.sub(self.removeTag, '\n', x) return x.strip()#百度貼吧爬蟲類class BDTB: def __init__(self, baseUrl, seeLZ): self.baseURL = baseUrl self.seeLZ = '?see_LZ=' + str(seeLZ) self.tool = Tool() self.file = None self.defaultFileTitile = u'百度貼吧' self.floor = 1 def getPage(self, pageNum): try: url = self.baseURL + self.seeLZ + '&pn=' + str(pageNum) request = urllib.request.Request(url) response = urllib.request.urlopen(request) return response.read().decode('utf-8') except urllib.error.URLError as e: print('串連百度貼吧失敗,原因為:' + e.reason) return None #擷取文章標題 def getTitle(self): page = self.getPage(1) pattern = re.compile('<h3 class="core_title_txt pull-left text-overflow.*?>(.*?)</h3>', re.S) result = re.search(pattern, page) if result: return result.group(1) else: return None #擷取文章一共有多少頁 def getPageNum(self): page = self.getPage(1) pattern = re.compile('<li class="l_reply_num.*?</span>.*?<span.*?>(.*?)</span>', re.S) result = re.search(pattern, page) if result: return result.group(1).strip() else: return None #擷取每一層樓的內容 def getContent(self, page): pattern = re.compile('<div id="post_content_.*?>(.*?)</div>', re.S) result = re.findall(pattern, page) return result def setFileTitle(self, title): if title is not None: self.file = open(title + '.txt', 'w') else: self.file = open(self.defaultFileTitile + '.txt', 'w') def writeData(self, contents): for item in contents: item = self.tool.replace(item) self.file.write(str(self.floor)+'樓--------------------------------------------------------------------\n') self.file.write(item + '\n') self.floor += 1baseUrl = 'http://tieba.baidu.com/p/4739169817'seeLZ = 1bdtb = BDTB(baseUrl, seeLZ)bdtb.setFileTitle(bdtb.getTitle())bdtb.writeData(bdtb.getContent(bdtb.getPage(1)))