抓取貓眼電影排行html
1. 抓取分析正則表達式
須要抓取的目標URL爲:http://maoyan.com/board/4,打開以後即可以查看到電影的排行,以下圖:json
(注:若是圖片看不清楚請右鍵點擊圖片經過新的標籤打開)服務器
排名第一的是霸王別姬,頁面中顯示的有效信息有影片名稱、主演、上映時間、上映地區、評分以及圖片等信息。將該頁面滾動到最下方,能夠發現還有分頁的列表,觀察點擊下一頁時,URL發生了怎樣的變化並記錄這個變化規律:函數
能夠發現第二頁的URL爲http://maoyan.com/board/4?offset=10,第三頁的URL爲http://maoyan.com/board/4?offset=20,以此類推。源碼分析
2. 抓取第一頁測試
定義一個函數用於抓取一個頁面,函數的參數就是url,將咱們要抓取頁面的url傳給函數,返回的結果就是服務器端的響應。url
import requests def get_one_page(url): headers = { 'User-Agent':'Mozilla/5.0(Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) Chrome/65.0.3325.162 Safari/537.36' } response = requests.get(url,headers=headers) if response.status_code == 200: return response.text return None
發送請求的函數很快就定義了,剩下的問題就是調用這個函數去發請求了,這裏咱們經過main方法來調用:spa
def main(): url = 'http://maoyan.com/board/4' html = get_one_page(url) print(html) if __name__ == '__main__': main()
能夠發現上面拿到的html就是第一頁的源碼了,接下來要作的就是從源碼裏面將咱們須要的信息抽取出來(這裏經過正則表達式實現):code
從源碼分析,一部電影的信息就用一個dd標籤存着。首先,須要提取電影的排名信息,而這個信息正好在calss爲board-index的i節點內,這裏使用非貪婪匹配來提取i節點內的信息,正則表達式爲:'<dd>.*?board-index.*?>(.*?)</i>';
隨後須要提取電影的圖片,能夠看到,後面有a節點,其內部有兩個img標籤,通過測試,第二個img標籤的data-src屬性就是圖片的鏈接,因此這裏提取的就是這個屬性的值:'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)"' ;
再日後,須要抓取電影的名稱,它在後面的p標籤內,class爲name,因此,能夠用name作一個標誌位,而後進一步提取到其內a節點的標籤體:'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>' ;
最後提取主演、上映時間、評分等內容:
'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>'
經過這樣的一個正則表達式就能夠將咱們須要的數據都提取出來了,而後這裏也是經過一個函數去解析一個網頁:
def parse_one_page(html): pattern = re.compile('<dd>.*?board-index.*?>(.*?)</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].strip(), 'actor':item[3].strip()[3:] if len(item[3]) > 3 else '', 'time':item[4].strip()[5:] if len(item[4]) > 5 else '', 'score':item[5].strip() + item[6].strip() }
這樣就能夠將咱們須要的數據封裝成一個對象返回,接下來就是數據的存儲了,這裏先使用文本直接存儲:
def write_to_file(content): with open('result.txt','a',encoding='utf-8') as f : f.write(json.dumps(content,ensure_ascii=False) + '\n')
這裏只是抓取並解析了一個網頁,然而咱們須要將整個排行榜抓取下來也很簡單,只須要循環去執行這些函數就好了:
def main(offset): url = 'http://maoyan.com/board/4?offset=' + str(offset) html = get_one_page(url) for item in parse_one_page(html): write_to_file(item) if __name__ == '__main__': for i in range(10): main(offset=i*10)
3. 完整代碼
import requests from requests.exceptions import RequestException import re import json import time def get_one_page(url): try: headers = { 'User-Agent':'Mozilla/5.0(Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36(KHTML,like Gecko) ' 'Chrome/65.0.3325.162 Safari/537.36' } response = requests.get(url,headers=headers) if response.status_code == 200: return response.text return None except RequestException: return None def parse_one_page(html): # 定義正則表達式,獲取電影的排名,名稱,主演,上映時間,評分 pattern = re.compile( '<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name.*?a.*?>(.*?)</a>.*?star.*?>(.*?)</p>.*?releasetime' + '.*?>(.*?)</p>.*?integer.*?>(.*?)</i>.*?fraction.*?>(.*?)</i>.*?</dd>',re.S ) items = re.findall(pattern,html) print(items) for item in items: yield { 'index':item[0], 'image':item[1], 'title':item[2].strip(), 'actor':item[3].strip()[3:] if len(item[3]) > 3 else '', 'time':item[4].strip()[5:] if len(item[4]) > 5 else '', 'score':item[5].strip() + item[6].strip() } def write_to_file(content): with open('result.txt','a',encoding='utf-8') as f: f.write(json.dumps(content,ensure_ascii=False) + '\n') def main(offset): url = 'http://maoyan.com/board/4?offset=' + str(offset) html = get_one_page(url) for item in parse_one_page(html): write_to_file(item) if __name__ == '__main__': for i in range(10): main(offset=i*10) # 防止反爬蟲機制 time.sleep(2)