python網路爬蟲(web spider)系統化整理總結(二):爬蟲python程式碼示例(兩種響應格式:json和html)
上一篇部落格(入門知識篇),對爬蟲有了一個基本的瞭解,但是具體怎麼實現一個爬蟲程式呢?
一般情況下,我們在瀏覽器獲取資訊,是向伺服器傳送一個http請求,要麼返回html頁面,要麼是ajax請求返回一串json資料,以更新當前網頁中區域性資訊。這裡用兩個例子分別學習下爬蟲的基本操作。
以下程式碼是基於python3.6環境。
一、百度線上翻譯的自動聯想功能
百度線上翻譯有這樣一個功能,如下圖,輸入一個字母w,下面黃框裡實時就會聯想出來幾個w開頭的單詞並有相應的翻譯,分析可見,是網頁自動傳送了一個post請求"https://fanyi.baidu.com/sug",並且只有一個引數。那麼我們怎麼利用這個API實現我們自己的聯想功能呢?
引數列表:
再看下其返回結果:
我們模擬瀏覽器傳送這個請求,將獲得這樣的json字串,解析之後,就可以拿到聯想到的單詞和相應的翻譯了:
# 使用requests import requests import json def fanyi(keyword): url = 'https://fanyi.baidu.com/sug' # 定義請求引數 data = { 'kw' : keyword } # 通過設定header頭,偽裝瀏覽器使用者 headers = {"User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)"} # 傳送post請求,抓取資訊 res = requests.post(url,data=data,headers=headers) # 解析結果並輸出 # 獲取響應的json字串 str_json = res.text # 把json轉字典 myjson = json.loads(str_json) # 先判斷data裡面是否有內容 if len(myjson['data'])==0: print("結果:沒有這個詞") print() else: # 遍歷結果,輸出單詞和相應的翻譯 for v in myjson['data']: print("--聯想到的單詞:"+v['k']) print("--翻譯:"+v['v']) print() if __name__ == '__main__': while True: keyword = input('輸入翻譯的單詞:') if keyword == 'q': print("-- 結束 --") break fanyi(keyword)
輸出結果如下:
二、使用requests分頁爬取貓眼電影中榜單欄目中TOP100榜的所有電影資訊,並將資訊寫入txt檔案和資料庫中(原始碼有詳細的註釋)
和上一個例子不同的是,這次返回的結果是html程式碼,我們需要通過正則表示式匹配解析出需要的內容;
這裡有兩點值得注意的:
1、使用requests方式請求得到的html原始碼,有可能和直接在瀏覽器選取其中一個元素看到的程式碼不一致,也有可能和右鍵檢視頁面原始碼不一致,對解析會造成一定的干擾。 這是因為瀏覽器可能是通過Ajax區域性更新的資料,解析之前要注意區分。
2、python中yield的使用(對python使用不是很熟悉的情況下,這個應用還是很新鮮、很特別的):
一個帶有 yield 的函式就是一個 generator,它和普通函式不同,生成一個 generator 看起來像函式呼叫,但不會執行任何函式程式碼,直到對其呼叫 next()(在 for 迴圈中會自動呼叫 next())才開始執行。雖然執行流程仍按函式的流程執行,但每執行到一個 yield 語句就會中斷,並返回一個迭代值,下次執行時從 yield 的下一個語句繼續執行。看起來就好像一個函式在正常執行的過程中被 yield 中斷了數次,每次中斷都會通過 yield 返回當前的迭代值。
yield 的好處是顯而易見的,把一個函式改寫為一個 generator 就獲得了迭代能力,比起用類的例項儲存狀態來計算下一個 next() 的值,不僅程式碼簡潔,而且執行流程異常清晰。
以下是第二個例子的原始碼:
# URL地址:http://maoyan.com/board/4 其中引數offset表示分頁的每頁起始條數-1
# 獲取資訊:{排名,圖片,標題,主演,放映時間,評分}
from requests.exceptions import RequestException
import requests
import re,time,json
import pymysql
def getPage(url):
'''爬取指定url頁面資訊'''
try:
#定義請求頭資訊(模擬瀏覽器)
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0'
}
# 執行爬取
res = requests.get(url,headers=headers)
#判斷響應狀態,並響應爬取內容
if res.status_code == 200:
return res.text
else:
return None
except RequestException:
return None
def parsePage(html):
'''解析爬取網頁中的內容,並返回欄位結果
這裡有個問題,使用requests獲取的網頁html和在瀏覽器中從頁面中選擇一個元素對應的html程式碼可能不一致
'''
#定義解析正則表示式(關於正則表示式的寫法用法,後面有機會再探討)
pat = '<i class="board-index board-index-[0-9]+">([0-9]+)</i>.*?' \
'<img data-src="(.*?)" alt="(.*?)" class="board-img" />.*?' \
'<p class="star">(.*?)</p>.*?' \
'<p class="releasetime">(.*?)</p>.*?' \
'<i class="integer">([0-9\.]+)</i>' \
'<i class="fraction">([0-9]+)</i>'
# print(html)
#執行解析
items = re.findall(pat,html,re.S)
#遍歷封裝資料並返回
for item in items:
print("item : ",item)
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'actor':item[3].strip()[3:],
'time':item[4].strip()[5:],
'score':item[5]+item[6],
}
def writeDB(content):
"""
寫入資料庫
:param content:
:return:
"""
print(content)
print(content["index"])
db = pymysql.connect("127.0.0.1", "root", "root", "myspider_001")
cursor = db.cursor()
sql = "insert into tb_results (index0,image,title,actor,time,score) \
values ('%s','%s','%s','%s','%s','%s')"% \
(content['index'],content['image'],content['title'],content['actor'],content['time'],content['score'])
print(sql)
try:
cursor.execute(sql)
print("qq")
db.commit()
except:
print("q")
db.rollback()
def writeFile(content):
'''執行檔案追加寫操作'''
#print(content)
with open("./result.txt",'a',encoding='utf-8') as f:
f.write(json.dumps(content,ensure_ascii=False) + "\n")
#json.dumps 序列化時對中文預設使用的ascii編碼.想輸出真正的中文需要指定ensure_ascii=False
def main(offset):
''' 主程式函式,負責排程執行爬蟲處理 '''
url = 'http://maoyan.com/board/4?offset=' + str(offset)
#print(url)
html = getPage(url)
#判斷是否爬取到資料,並呼叫解析函式
if html:
for item in parsePage(html):
writeFile(item)
writeDB(item)
# 判斷當前執行是否為主程式執行,並遍歷呼叫主函式爬取資料
if __name__ == '__main__':
# 前100名,每頁10名,分頁引數offset 0 10 20 ...90
for i in range(10):
main(offset=i*10)
time.sleep(1)
學完這兩個基本的例子,就對爬蟲有了一個初步的認識。
後面還會繼續學習,寫下來,一方面是個總結和記錄,一方面希望有可能幫到和我一樣的初學者。