1. 程式人生 > >14-Requests+正則表示式爬取貓眼電影

14-Requests+正則表示式爬取貓眼電影

'''Requests+正則表示式爬取貓眼電影TOP100'''
'''
流程框架:
抓去單頁內容:利用requests請求目標站點,得到單個網頁HTML程式碼,返回結果。
正則表示式分析:根據HTML程式碼分析得到電影的名稱、主演、上映時間、評分、圖片連結等資訊。
儲存至檔案:通過檔案的形式儲存結果,每一部電影一個結果一行Json字串。
開啟迴圈及多執行緒:對多頁內容遍歷,開啟多執行緒提高抓取速度。
'''
import requests
import re
from requests.exceptions import RequestException
import json
from multiprocessing import Pool

def get_one_page(url,headers):
'''得到網頁原始碼'''
try:
#此處必須要傳入headers引數,否則因為有些網站伺服器的反爬機制,會返回403 Forbidden。參考:https://blog.csdn.net/lv0817/article/details/79185322
response = requests.get(url=url,headers=headers) #這裡要注意,必須使用url=url,headers=headers的格式,否則傳參無效。
if response.status_code == 200:
return response.text
return None
#可以檢視requests庫的官方文件的Exceptions模組,可知RequestException為所有異常的父類或間接父類。
except RequestException:
return None

def parse_one_page(html):
'''解析得到的網頁原始碼'''
#編譯正則表示式
pattern = re.compile('<dd>.*?board-index.*?>(\d+)</i>.*?data-src="(.*?)".*?name"><a.*?>(.*?)</a>.*?star">(.*?)</p>'
'.*?releasetime">(.*?)</p>.*?integer">(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>',re.S)
items = re.findall(pattern,html)
#建立一個生成器
for item in items:
yield {
'index':item[0],
'image':item[1],
'title':item[2],
'actor':item[3].strip()[3:],
'time':item[4][5:],
'score':item[5]+item[6]
}

def write_to_file(content):
'''解析好的資料寫入到檔案'''
with open('result.txt','a',encoding='utf-8') as f: #'a'表示內容可追加。當有中文時,指定編碼utf-8防止亂碼。
#json.dumps序列化時對中文預設使用的ascii編碼.想輸出真正的中文需要指定ensure_ascii = False。
f.write(json.dumps(content,ensure_ascii=False) + '\n') #json.dumps將字典轉換為字串
f.close()

def main(offset):
url = "http://maoyan.com/board/4?offset=" + str(offset) #點選下一頁觀察網址可知
headers = {
'User-Agent': 'Mozilla/5.0(Macintosh;Intel Mac OS X 10_11_4)AppleWebKit/537.36(KHTML,like Gecko)Chrome/52.0.2743.116 Safari/537.36'
}
html = get_one_page(url,headers)
#遍歷生成器
for item in parse_one_page(html):
print(item)
write_to_file(item)

if __name__ == '__main__':
# for i in range(10):
# main(i*10)
#如果要實現秒抓的話,就要使用多程序。
#程序池提供指定數量的程序供使用者呼叫,如果有新的請求提交到程序池,池子還沒有滿,它就會建立新的程序來執行請求,如果池子滿了就先等待。
#構造程序池
pool = Pool() #宣告一個程序池
pool.map(main,[i*10 for i in range(10)]) #第一個引數是方法名,第二個引數是可遍歷物件。map方法作用是,拿出可遍歷陣列中的每一個值當做函式的引數,然後建立一個個的程序,放到程序池裡面去執行。