前言:
學習python3爬蟲有一段時間了,熟悉了爬蟲的一些基本原理和基本庫的使用,本次就准備利用requests庫和正則表達式來抓取貓眼電影排行TOP100的相關內容。
1、本次目標:
爬取貓眼電影排行TOP100的電影相關信息,包括:名稱、圖片、演員、時間、評分,排名。提取站點的URL為http://maoyan.com/board/4,提取的結果以文本形式保存下來。
2、准備工作
只需要安裝好requests庫即可。
安裝方式有很多種,這里只簡單的介紹一下通過pip這個包管理工具來安裝。
在命令行界面中輸入pip3 install requests即可完成安裝。(無論是windows、linux、還是mac,都可以使用該方式)
完成之后可以導入requests模塊進行測試:
>python Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import requests >>>
如果沒有錯誤提示,就證明已經成功安裝了。
3、抓取分析
首先進入目標站點http://maoyan.com/board/4,如下圖,可以看到有電影的排名、演員、時間、評分等信息,翻到頁面底部,如下圖,可以發現,每個頁面有10部電影,點擊下一頁可看到站點的URL變為了http://maoyan.com/board/4?offset=10,如下圖,里面是排名11-20的電影。也就是說要獲取TOP100的電影信息,只需要請求offset=0,10,20...90的頁面,然后再利用正則表達式爬取每一頁所需要的電影信息即可。



4、抓取頁面
這里構建一個get_one_page()函數,用來抓取每一個單獨頁面的內容,初步代碼實現如下:
1 import requests 2 3 4 def get_one_page(): 5 url = 'http://maoyan.com/board/4' 6 headers = { 7 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 ' 8 '(KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36' 9 } 10 response = requests.get(url=url, headers=headers) 11 print(response.text) 12 13 14 get_one_page()
代碼運行之后,就獲取到了頁面的源代碼,接下來就運用正則表達式提取出所需要的信息。
5、正則提取
回到網頁,按F12在開發者模式下的NETWORK監聽組件中查看到源代碼,如下圖。


在源代碼中可以看到電影的相關信息,這里用紅色箭頭從上至下分別標記出了電影的排名、圖片、電影名、演員、上映時間以及評分所在的位置。接下來只需要為每一部分的信息寫出對應的正則表達式即可獲取到相應的信息。
先以電影排名為例,可以看到每一個電影部分的所有信息都包含在<dd>..</dd>節點中,而電影排名的信息是在class為board-index的i節點中,所以這里利用非貪婪的匹配原則提取該節點內的信息,正則表達式可寫為:<dd>.*?"board-index.*?>(.*?)</i>
接下來獲取電影圖片。可以看到電影圖片的信息在img data-src的a節點中,正則表達式可寫為:<dd>.*?data-src="(.*?)".*?</a>
同樣,電影名稱的信息在name為標志位title=""的a節點中,正則表達式可寫為:<dd>.*?class="name".*?title="(.*?)".*?</a>
按照以上方法,最后可以得到完整的正則表達式為:<dd>.*?board-index.*?>(\d+?)</i>.*?data-src="(.*?)".*?</a>.*?class="name".*?title="(.*?)".*?</a>.*?class="star".+?(.*?)</p>.*?class="releasetime".+?(.*?)</p>.*?class="integer".+?(.*?)</i>.*?"fraction".+?(.*?)</i>.*?</dd>
接下來只需要構建一個解析頁面的函數parse_one_page(),用來得到所需要的電影信息,代碼實現如下:
1 def parse_one_page(html): 2 pattern = re.compile( 3 r'<dd>.*?board-index.*?>(\d+?)</i>' 4 r'.*?data-src="(.*?)".*?</a>' 5 r'.*?class="name".*?title="(.*?)".*?</a>' 6 r'.*?class="star".+?(.*?)</p>' 7 r'.*?class="releasetime".+?(.*?)</p>' 8 r'.*?class="integer".+?(.*?)</i>' 9 r'.*?"fraction".+?(.*?)</i>.*?</dd>', re.S 10 ) 11 re_lists = re.findall(pattern, html) 12 for re_list in re_lists: 13 yield { 14 'index': re_list[0], 15 'image': re_list[1], 16 'title': re_list[2], 17 'actor': re_list[3].strip()[3:], 18 'time': re_list[4].strip()[5:], 19 'score': re_list[5] + re_list[6] 20 }
# 這里用compile()方法,將正則字符串構建成正則對象,以便復用。其中re.S,表示(.)這個通配符能夠匹配到包括換行符在內的所有字符。yield迭代返回一個包含電影全部信息的字典。關於yield的知識鏈接:http://www.runoob.com/w3cnote/python-yield-used-analysis.html
代碼輸出結果如下:
{"index": "1", "image": "http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c", "title": "霸王別姬", "actor": "張國榮,張豐毅,鞏俐", "time": "1993-01-01", "score": "9.6"}
{"index": "2", "image": "http://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c", "title": "肖申克的救贖", "actor": "蒂姆·羅賓斯,摩根·弗里曼,鮑勃·岡頓", "time": "1994-10-14(美國)", "score": "9.5"}
{"index": "3", "image": "http://p0.meituan.net/movie/54617769d96807e4d81804284ffe2a27239007.jpg@160w_220h_1e_1c", "title": "羅馬假日", "actor": "格利高里·派克,奧黛麗·赫本,埃迪·艾伯特", "time": "1953-09-02(美國)", "score": "9.1"}
{"index": "4", "image": "http://p0.meituan.net/movie/e55ec5d18ccc83ba7db68caae54f165f95924.jpg@160w_220h_1e_1c", "title": "這個殺手不太冷", "actor": "讓·雷諾,加里·奧德曼,娜塔莉·波特曼", "time": "1994-09-14(法國)", "score": "9.5"}
{"index": "5", "image": "http://p1.meituan.net/movie/f5a924f362f050881f2b8f82e852747c118515.jpg@160w_220h_1e_1c", "title": "教父", "actor": "馬龍·白蘭度,阿爾·帕西諾,詹姆斯·肯恩", "time": "1972-03-24(美國)", "score": "9.3"}
{"index": "6", "image": "http://p1.meituan.net/movie/0699ac97c82cf01638aa5023562d6134351277.jpg@160w_220h_1e_1c", "title": "泰坦尼克號", "actor": "萊昂納多·迪卡普里奧,凱特·溫絲萊特,比利·贊恩", "time": "1998-04-03", "score": "9.5"}
{"index": "7", "image": "http://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c", "title": "唐伯虎點秋香", "actor": "周星馳,鞏俐,鄭佩佩", "time": "1993-07-01(中國香港)", "score": "9.2"}
{"index": "8", "image": "http://p0.meituan.net/movie/b076ce63e9860ecf1ee9839badee5228329384.jpg@160w_220h_1e_1c", "title": "千與千尋", "actor": "柊瑠美,入野自由,夏木真理", "time": "2001-07-20(日本)", "score": "9.3"}
{"index": "9", "image": "http://p0.meituan.net/movie/46c29a8b8d8424bdda7715e6fd779c66235684.jpg@160w_220h_1e_1c", "title": "魂斷藍橋", "actor": "費雯·麗,羅伯特·泰勒,露塞爾·沃特森", "time": "1940-05-17(美國)", "score": "9.2"}
{"index": "10", "image": "http://p0.meituan.net/movie/230e71d398e0c54730d58dc4bb6e4cca51662.jpg@160w_220h_1e_1c", "title": "亂世佳人", "actor": "費雯·麗,克拉克·蓋博,奧利維婭·德哈維蘭", "time": "1939-12-15(美國)", "score": "9.1"}
這樣就成功得將貓眼TOP1-10的電影抓取下來了,接下來只需要獲取剩余頁面,用同樣的方式即可。
6、頁面獲取
根據上面的分析可知,只需要分別請求URL為http://maoyan.com/board/4?offset=0,10,20...90的頁面。所以這里構建一個url_list()函數,設置一個offset參數來標記頁面。代碼實現如下:
1 def url_list(offset): 2 if offset == 0: 3 page_url = 'http://maoyan.com/board/4' 4 return page_url 5 6 else: 7 page_url = 'http://maoyan.com/board/4' + '?offset=' + str(offset) 8 return page_url
7、保存數據
對於抓取到的數據,這里構建一個write()函數,直接將數據寫入文本文件中。通過JSON庫里的dumps()方法實現字典的序列化,並指定ensure_ascii參數為False,這樣可以保證輸出結果是中文形式而不是Unicode編碼。代碼實現如下:
1 def write(final_result): 2 with open('貓眼電影top100.txt', 'a', encoding='utf-8') as file: 3 file.write(json.dumps(final_result, ensure_ascii=False) + '\n')
8、整合代碼
構建一個主函數main(),整合所有函數功能,完成抓取。
在主函數中,首先定義一個包含0、10、20...90的offset_list列表,遍歷列表中的每一個offset值得到每一個頁面URL的值;然后傳給get_one_page()函數來得到每一個頁面;再將得到頁面的響應體傳給parse_one_page()解析出電影信息;最后把解析出的電影信息寫入文本文件中保存。代碼實現如下:
1 def main(): 2 offset_list = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 3 for offset in offset_list: 4 url = url_list(offset) 5 html = get_one_page(url) 6 result = parse_one_page(html) 7 for i in range(10): 8 final_result = next(result) 9 print(final_result) 10 write(final_result)
9、完整代碼
到此為止,貓眼電影TOP100的爬蟲就全部完成了,最后稍微整理完善,附上完整代碼如下:
1 import requests 2 import re 3 import json 4 import time 5 from requests.exceptions import RequestException 6 7 8 # 抓取單個頁面 9 def get_one_page(url): 10 try: 11 headers = { 12 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 ' 13 '(KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36' 14 } 15 response = requests.get(url=url, headers=headers) 16 if response.status_code == 200: 17 return response.text 18 return None 19 except RequestException: 20 return None 21 22 23 # 解析單個頁面 24 def parse_one_page(html): 25 # 正則表達式 26 pattern = re.compile( 27 r'<dd>.*?board-index.*?>(\d+?)</i>' 28 r'.*?data-src="(.*?)".*?</a>' 29 r'.*?class="name".*?title="(.*?)".*?</a>' 30 r'.*?class="star".+?(.*?)</p>' 31 r'.*?class="releasetime".+?(.*?)</p>' 32 r'.*?class="integer".+?(.*?)</i>' 33 r'.*?"fraction".+?(.*?)</i>.*?</dd>', re.S 34 ) 35 re_lists = re.findall(pattern, html) 36 for re_list in re_lists: 37 yield { 38 'index': re_list[0], 39 'image': re_list[1], 40 'title': re_list[2], 41 'actor': re_list[3].strip()[3:], 42 'time': re_list[4].strip()[5:], 43 'score': re_list[5] + re_list[6] 44 } 45 46 47 # 獲取所有URL 48 def url_list(offset): 49 if offset == 0: 50 page_url = 'http://maoyan.com/board/4' 51 return page_url 52 53 else: 54 page_url = 'http://maoyan.com/board/4' + '?offset=' + str(offset) 55 return page_url 56 57 58 # 保存數據 59 def write(final_result): 60 with open('貓眼電影top100.txt', 'a', encoding='utf-8') as file: 61 file.write(json.dumps(final_result, ensure_ascii=False) + '\n') 62 63 64 # 主函數 65 def main(): 66 offset_list = [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 67 for offset in offset_list: 68 url = url_list(offset) 69 html = get_one_page(url) 70 result = parse_one_page(html) 71 for i in range(10): 72 final_result = next(result) 73 print(final_result) 74 write(final_result) 75 76 77 if __name__ == '__main__': 78 main() 79 time.sleep(1) # 延時等待
10、運行結果
最后運行代碼,得到結果如下:
{'index': '1', 'image': 'http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg@160w_220h_1e_1c', 'title': '霸王別姬', 'actor': '張國榮,張豐毅,鞏俐', 'time': '1993-01-01', 'score': '9.6'}
{'index': '2', 'image': 'http://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', 'title': '肖申克的救贖', 'actor': '蒂姆·羅賓斯,摩根·弗里曼,鮑勃·岡頓', 'time': '1994-10-14(美國)', 'score': '9.5'}
{'index': '3', 'image': 'http://p0.meituan.net/movie/54617769d96807e4d81804284ffe2a27239007.jpg@160w_220h_1e_1c', 'title': '羅馬假日', 'actor': '格利高里·派克,奧黛麗·赫本,埃迪·艾伯特', 'time': '1953-09-02(美國)', 'score': '9.1'}
{'index': '4', 'image': 'http://p0.meituan.net/movie/e55ec5d18ccc83ba7db68caae54f165f95924.jpg@160w_220h_1e_1c', 'title': '這個殺手不太冷', 'actor': '讓·雷諾,加里·奧德曼,娜塔莉·波特曼', 'time': '1994-09-14(法國)', 'score': '9.5'}
{'index': '5', 'image': 'http://p1.meituan.net/movie/f5a924f362f050881f2b8f82e852747c118515.jpg@160w_220h_1e_1c', 'title': '教父', 'actor': '馬龍·白蘭度,阿爾·帕西諾,詹姆斯·肯恩', 'time': '1972-03-24(美國)', 'score': '9.3'}
{'index': '6', 'image': 'http://p1.meituan.net/movie/0699ac97c82cf01638aa5023562d6134351277.jpg@160w_220h_1e_1c', 'title': '泰坦尼克號', 'actor': '萊昂納多·迪卡普里奧,凱特·溫絲萊特,比利·贊恩', 'time': '1998-04-03', 'score': '9.5'}
...
{'index': '96', 'image': 'http://p1.meituan.net/movie/36a893c53a13f9bb934071b86ae3b5c492427.jpg@160w_220h_1e_1c', 'title': '愛·回家', 'actor': '俞承豪,金藝芬,童孝熙', 'time': '2002-04-05(韓國)', 'score': '9.0'}
{'index': '97', 'image': 'http://p1.meituan.net/movie/9bff56ed3ea38bb1825daa1d354bc92352781.jpg@160w_220h_1e_1c', 'title': '黃金三鏢客', 'actor': '克林特·伊斯特伍德,李·范·克里夫,埃里·瓦拉赫', 'time': '1966-12-23(意大利)', 'score': '8.9'}
{'index': '98', 'image': 'http://p1.meituan.net/movie/ed50b58bf636d207c56989872a91f4cf305138.jpg@160w_220h_1e_1c', 'title': '我愛你', 'actor': '宋在浩,李順才,尹秀晶', 'time': '2011-02-17(韓國)', 'score': '9.0'}
{'index': '99', 'image': 'http://p1.meituan.net/movie/a1634f4e49c8517ae0a3e4adcac6b0dc43994.jpg@160w_220h_1e_1c', 'title': '遷徙的鳥', 'actor': '雅克·貝漢,Philippe Labro', 'time': '2001-12-12(法國)', 'score': '9.1'}
{'index': '100', 'image': 'http://p0.meituan.net/movie/3e5f5f3aa4b7e5576521e26c2c7c894d253975.jpg@160w_220h_1e_1c', 'title': '英雄本色', 'actor': '狄龍,張國榮,周潤發', 'time': '2017-11-17', 'score': '9.2'}

可以看到,電影信息已經全部成功爬取下來,並且保存到了文本文件中。抓取貓眼電影排行TOP100,大功告成!
結語:
學習爬蟲的時間不長,寫篇博客也算是對知識的溫習和對自己成長的記錄,有不足之處希望能諒解並且指出。
