1 目標
貓眼榜單TOP100:https://www.maoyan.com/board
2 流程框架
- 抓取單頁內容:利用requests請求目標站點,得到單個網頁HTML代碼,返回結果。
- 正則表達式分析:根據HTML代碼分析得到電影名稱,主演,上映時間,評分,圖片鏈接等信息。
- 保存至文件:通過文件的形式將結果保存,每一步電影一個結果一行json字符串。
- 開啟循環及多線程:對多頁內容遍歷,開啟多線程提高抓取速度。
3 實戰
1.抓取單頁內容
import requests
from requests.exceptions import RequestException# 提取單頁內容,用try,except防止掛機
def get_one_page(url):try:response = requests.get(url)if response.status_code == 200:#如果狀態碼為200,請求成功return response.textreturn response.status_code #請求失敗,返回狀態碼結果except RequestException:return Nonedef main():url = "https://www.maoyan.com/board/4"html = get_one_page(url)print(html)
if __name__ == '__main__':main()
url路徑:下圖可知:第一頁offset = 0,第二頁offset=10
respnse查看內容:Network 選項->篩選Doc
返回:
如果報了403狀態碼:
請求是加上headers
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'}
#提取單頁內容,用try,except方便找bug
def get_one_page(url):try:response = requests.get(url, headers=headers)#傳入headers參數if response.status_code == 200:return response.textreturn response.status_codeexcept RequestException:return None
2 正則表達式分析
根據HTML代碼分析得到電影名稱,主演,上映時間,評分,圖片鏈接等信息。
HTML的結構:
紅色箭頭是需要提取的信息,正則表達式如下:
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)# items是一個list,提取信息成字典形式for item in items:yield { # 構造一個字典'index': item[0],'image':item[1],'title':item[2],'actor':item[3].strip()[3:],#做切片,去掉“主演:“這3個字符'time':item[4].strip()[5:],'score':item[5]+item[6] #將小數點前后的數字拼接起來}return itemsdef main():url = "https://www.maoyan.com/board/4"html = get_one_page(url)for item in parse_one_page(html):print(item)
效果如下:
3 保存至文件
def write_to_file(content):with open('result.txt','a',encoding='utf-8') as f:f.write(json.dumps(content, ensure_ascii=False) + '\n') # 不允許寫入ascii碼f.close()def main():url = "https://www.maoyan.com/board/4"html = get_one_page(url)for item in parse_one_page(html):print(item)write_to_file(item)
效果如下:
4 開啟循環及多線程
方式一:
def main(offset):url = "https://www.maoyan.com/board/4?offset="+str(offset)html = get_one_page(url)for item in parse_one_page(html):print(item)write_to_file(item)if __name__ == '__main__':for i in range(10):main(i*10)
方式二:
from multiprocessing import Pool
if __name__ == '__main__':pool = Pool() #創建一個進程池pool.map(main,[i*10 for i in range(10)])
4 整體代碼
import requests
from requests.exceptions import RequestException
import re
import json
from multiprocessing import Poolheaders = {'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'}# 提取單頁內容,用try,except方便找bug
def get_one_page(url):try:response = requests.get(url, headers=headers) # 傳入headers參數if response.status_code == 200:return response.textreturn response.status_codeexcept RequestException: # 捕獲這個類型的異常return Nonedef parse_one_page(html): # 定義一個函數用來解析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)# items是一個list,其中的每個內容都是一個元組# 將雜亂的信息提取并格式化,變成一個字典形式for item in items:yield { # 構造一個字典'index': item[0],# 'image': item[1],'title': item[2],'actor': item[3].strip()[3:], # 做一個切片,去掉“主演:”這3個字符'time': item[4].strip()[5:], # 做一個切片,去掉“上映時間:”這5個字符'score': item[5] + item[6] # 將小數點前后的數字拼接起來}def write_to_file(content):with open('result.txt', 'a', encoding='utf-8') as f:# a表示模式是“追加”;采用utf-8編碼可以正常寫入漢字f.write(json.dumps(content, ensure_ascii=False) + '\n') # 不允許寫入ascii碼# content是一個字典,我們需要轉換成字符串形式,注意導入json庫f.close()def main(offset):url = 'https://maoyan.com/board/4?offset=' + str(offset) # 把offset參數以字符串形式添加到url中html = get_one_page(url)for item in parse_one_page(html): # item是一個生成器print(item)write_to_file(item)if __name__ == '__main__':pool = Pool() # 創建一個進程池pool.map(main, [i * 10 for i in range(10)]) # map方法創建進程(不同參數的main),并放到進程池中