待爬取的網頁地址為https://maoyan.com/board/4,本次以requests、BeautifulSoup css selector為路線進行爬取,最終目的是把影片排名、圖片、名稱、演員、上映時間與評分提取出來並保存到文件。
初步分析:所有網頁上展示的內容后台都是通過代碼來完成的,所以,不管那么多,先看源代碼
F12打開chrome的調試工具,從下面的圖可以看出,實際上每一個電影選項(排名、分數、名字等)都被包括在dd標簽中。
為了能把這些影片信息爬取出來,可以有以下兩種思路。
思路一:把電影的每一個要素的列表先提取出來,類似如下:
titile = ['霸王別姬','肖申克的救贖'....],index = [1,2...],
最后從各個列表中選中對應的item拼接成一個個新的列表或字典類型,
類似如下:result = [{'title':'霸王別姬','index':'1'},{'title':'肖申克的救贖','index':'2'.....}
分析:因為要多次進行遍歷,思路一的整體邏輯較混亂,容易出錯
思路二:把每一個dd標簽作為一個整體提取為一個列表,然后對列表的每一項(包含每部影片的各項信息)進行解析提取
分析:很明顯,相對第一種思路,第二種思路就更加的清晰明了
下面通過代碼來實現思路二的方式:
第一步:獲取當前頁的網頁源代碼
def get_current_page(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' } try: r = requests.get(url, headers=headers) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except RequestException: return None
第二步:解析當前網頁提取出影片信息
def parse_html(html): soup = BeautifulSoup(html, 'lxml') dd = soup.select('dd') #css選擇器,select是選取所有符合條件的節點,select_one是選取第一個符合條件的節點 for result in dd:
#生成器的方式更省內存 yield { 'index': result.select_one('.board-index').text, #獲取影片排名 'title':result.select_one('.image-link')['title'], #獲取影片名字 'image':result.select_one('.poster-default')['src'], #獲取影片圖片鏈接 'star':result.select_one('.star').text.strip(), #獲取演員信息 'realeasetime':result.select_one('.releasetime').text.strip(),#獲取上映時間 'score':result.select_one('.integer').text+result.select_one('.fraction').text #獲取影片得分 }
第三步:將結果保存到文件
def save_to_file(content): with open('result.txt', 'a', encoding='utf-8') as f: #以追加的形式寫入文件 f.write(json.dumps(content, ensure_ascii=False) + '\n')
以上實現了單頁影片信息的爬取與存儲,下面探索怎么實現翻頁后的頁面爬取
思路:既然要翻頁,那就先點擊下一頁看看,找找規律,從下圖可以看出url后面多了個?offset=10,繼續翻頁顯示為?offset=20,最后一頁顯示為?offset=90,這就找到規律了,每一個url后面的url都等於頁面號x10(頁面號從0計數)。
得出規律之后我們開始寫主函數
第四步:寫主函數
def main(offset): url = 'https://maoyan.com/board/4?offset=' + str(offset * 10) html = get_current_page(url) for result in parse_html(html): print(result) save_to_file(result)
第五步:寫函數入口
if __name__ == '__main__': depth = 10
for i in range(depth): main(i)
最后運行的結果:
整個的爬取過程就是這樣,完整代碼查看可以點擊這里