【網路爬蟲學習】實戰,爬取網頁以及貼吧資料
實戰一
抓取您想要的網頁,並將其儲存至本地計算機。
首先我們對要編寫的爬蟲程式進行簡單地分析,該程式可分為以下三個部分:
- 拼接 url 地址
- 傳送請求
- 將照片儲存至本地
明確邏輯後,我們就可以正式編寫爬蟲程式了。
匯入所需模組
from urllib import request, parse
拼接 URL 地址
定義 URL 變數,拼接 url 地址。程式碼如下所示:
url = 'http://www.baidu.com/s?wd={}' word = input('請輸入想要搜尋的內容:') params = parse.quote(word) full_url = url.format(params)
向URL傳送請求
傳送請求主要分為以下幾個步驟:
- 建立請求物件-Request
- 獲取響應物件-urlopen
- 獲取響應內容-read
程式碼如下所示:
# 重構請求頭 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0' } # 建立請求對應 req = request.Request(url=full_url, headers=headers) # 獲取響應物件 res = request.urlopen(req) # 獲取響應內容 html = res.read().decode('utf-8')
儲存為本地檔案
把爬取的照片儲存至本地,此處需要使用 Python 程式設計的檔案 IO 操作,程式碼如下:
filename = word + '.html'
with open(filename, 'w', encoding='utf-8') as f:
f.write(html)
完整程式如下所示:
from urllib import request, parse # 1.拼url地址 url = 'http://www.baidu.com/s?wd={}' word = input('請輸入想要搜尋的內容:') params = parse.quote(word) full_url = url.format(params) # 2.發請求儲存到本地 # 重構請求頭 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0' } # 建立請求對應 req = request.Request(url=full_url, headers=headers) # 獲取響應物件 res = request.urlopen(req) # 獲取響應內容 html = res.read().decode('utf-8') # 3.儲存檔案至當前目錄 filename = word + '.html' with open(filename, 'w', encoding='utf-8') as f: f.write(html)
嘗試執行程式,並輸入 RioTianの部落格園,確認搜尋,然後您會在當前的工作目錄中找到“RioTianの部落格園.html”檔案。
函數語言程式設計修改程式
Python 函數語言程式設計可以讓程式的思路更加清晰、易懂。接下來,使用函式程式設計的思想更改上面程式碼。
定義相應的函式,通過呼叫函式來執行爬蟲程式。修改後的程式碼如下所示:
from urllib import request, parse
# 拼接URL地址
def get_url(word):
url = 'http://www.baidu.com/s?{}'
# 此處使用urlencode()進行編碼
params = parse.urlencode({'wd': word})
url = url.format(params)
return url
# 發請求,儲存本地檔案
def request_url(url, filename):
headers = {
'User-Agent':
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:6.0) Gecko/20100101 Firefox/6.0'
}
# 請求物件 + 響應物件 + 提取內容
req = request.Request(url=url, headers=headers)
res = request.urlopen(req)
html = res.read().decode('utf-8')
# 儲存檔案至本地
with open(filename, 'w', encoding='utf-8') as f:
f.write(html)
# 主程式入口
if __name__ == '__main__':
word = input('請輸入搜尋內容:')
url = get_url(word)
filename = word + '.html'
request_url(url, filename)
除了使用函數語言程式設計外,也可以使用面向物件的程式設計方法(實戰二),在後續內容中會做相應介紹。
實戰二
抓取百度貼吧(https://tieba.baidu.com/)頁面,比如 Python爬蟲吧、程式設計吧,只抓取貼吧的前 5 個頁面即可。
判斷頁面型別
通過簡單的分析可以得知,待抓取的百度貼吧頁面屬於靜態網頁,分析方法非常簡單:開啟百度貼吧,搜尋“Python爬蟲”,在出現的頁面中複製任意一段資訊,比如“爬蟲需要 http 代理的原因”,然後點選右鍵選擇檢視原始碼,並使用 Ctrl+F 快捷鍵在原始碼頁面搜尋剛剛複製的資料,如下所示:
由上圖可知,頁面內的所有資訊都包含在原始碼頁中,資料並不需要從資料庫另行載入,因此該頁面屬於靜態頁面。
尋找URL變化規律
接下來尋找要爬取頁面的 URL 規律,搜尋“Python爬蟲”後,此時貼吧第一頁的的 url 如下所示:
https://tieba.baidu.com/f?ie=utf-8&kw=python爬蟲&fr=search
點選第二頁,其 url 資訊如下:
https://tieba.baidu.com/f?kw=python爬蟲&ie=utf-8&pn=50
點選第三頁,url 資訊如下:
https://tieba.baidu.com/f?kw=python爬蟲&ie=utf-8&pn=100
重新點選第一頁,url 資訊如下:
https://tieba.baidu.com/f?kw=python爬蟲&ie=utf-8&pn=0
如果還不確定,您可以繼續多瀏覽幾頁。最後您發現 url 具有兩個查詢引數,分別是 kw 和 pn,並且 pn 引數具有規律性,如下所示:
第n頁:pn=(n-1)*50
#引數params
pn=(page-1)*50
params={
'kw':name,
'pn':str(pn)
}
url 地址可以簡寫為:
https://tieba.baidu.com/f?kw=python爬蟲&pn=450
編寫爬蟲程式
下面以類的形式編寫爬蟲程式,並在類下編寫不同的功能函式,程式碼如下所示:
from urllib import request,parse
import time
import random
from ua_info import ua_list #使用自定義的ua池
#定義一個爬蟲類
class TiebaSpider(object):
#初始化url屬性
def __init__(self):
self.url='http://tieba.baidu.com/f?{}'
# 1.請求函式,得到頁面,傳統三步
def get_html(self,url):
req=request.Request(url=url,headers={'User-Agent':random.choice(ua_list)})
res=request.urlopen(req)
#windows會存在亂碼問題,需要使用 gbk解碼,並使用ignore忽略不能處理的位元組
#linux不會存在上述問題,可以直接使用decode('utf-8')解碼
html=res.read().decode("gbk","ignore")
return html
# 2.解析函式,此處程式碼暫時省略,還沒介紹解析模組
def parse_html(self):
pass
# 3.儲存檔案函式
def save_html(self,filename,html):
with open(filename,'w') as f:
f.write(html)
# 4.入口函式
def run(self):
name=input('輸入貼吧名:')
begin=int(input('輸入起始頁:'))
stop=int(input('輸入終止頁:'))
# +1 操作保證能夠取到整數
for page in range(begin,stop+1):
pn=(page-1)*50
params={
'kw':name,
'pn':str(pn)
}
#拼接URL地址
params=parse.urlencode(params)
url=self.url.format(params)
#發請求
html=self.get_html(url)
#定義路徑
filename='{}-{}頁.html'.format(name,page)
self.save_html(filename,html)
#提示
print('第%d頁抓取成功'%page)
#每爬取一個頁面隨機休眠1-2秒鐘的時間
time.sleep(random.randint(1,2))
#以指令碼的形式啟動爬蟲
if __name__=='__main__':
start=time.time()
spider=TiebaSpider() #例項化一個物件spider
spider.run() #呼叫入口函式
end=time.time()
#檢視程式執行時間
print('執行時間:%.2f'%(end-start)) #爬蟲執行時間
程式執行後,爬取的檔案將會儲存至 Pycharm 當前工作目錄,輸出結果:
輸入貼吧名:python爬蟲
輸入起始頁:1
輸入終止頁:2
第1頁抓取成功
第2頁抓取成功
執行時間:12.25
以面向物件方法編寫爬蟲程式時,思路簡單、邏輯清楚,非常容易理解,上述程式碼主要包含了四個功能函式,它們分別負責了不同的功能,總結如下:
1) 請求函式
請求函式最終的結果是返回一個 HTML 物件,以方便後續的函式呼叫它。
2) 解析函式
解析函式用來解析 HTML 頁面,常用的解析模組有正則解析模組、bs4 解析模組。通過分析頁面,提取出所需的資料,在後續內容會做詳細介紹。
3) 儲存資料函式
該函式負責將抓取下來的資料保至資料庫中,比如 MySQL、MongoDB 等,或者將其儲存為檔案格式,比如 csv、txt、excel 等。
4) 入口函式
入口函式充當整個爬蟲程式的橋樑,通過呼叫不同的功能函式,實現資料的最終抓取。入口函式的主要任務是組織資料,比如要搜尋的貼吧名、編碼 url 引數、拼接 url 地址、定義檔案儲存路徑。
爬蟲程式結構
用面向物件的方法編寫爬蟲程式時,邏輯結構較為固定,總結如下:
# 程式結構
class xxxSpider(object):
def __init__(self):
# 定義常用變數,比如url或計數變數等
def get_html(self):
# 獲取響應內容函式,使用隨機User-Agent
def parse_html(self):
# 使用正則表示式來解析頁面,提取資料
def write_html(self):
# 將提取的資料按要求儲存,csv、MySQL資料庫等
def run(self):
# 主函式,用來控制整體邏輯
if __name__ == '__main__':
# 程式開始執行時間
spider = xxxSpider()
spider.run()
注意:掌握以上程式設計邏輯有助於您後續的學習。
爬蟲程式隨機休眠
在入口函式程式碼中,包含了以下程式碼:
# 每爬取一個頁面隨機休眠1-2秒鐘的時間
time.sleep(random.randint(1,2))
爬蟲程式訪問網站會非常快,這與正常人類的點選行為非常不符。因此,通過隨機休眠可以使爬蟲程式模仿成人類的樣子點選網站,從而讓網站不易察覺是爬蟲訪問網站,但這樣做的代價就是影響程式的執行效率。
聚焦爬蟲是一種執行效率較低的程式,提升其效能,是業界一直關注的問題,由此也誕生了效率較高的 Python 爬蟲框架 Scrapy。
The desire of his soul is the prophecy of his fate
你靈魂的慾望,是你命運的先知。