python抓取豆瓣電影top250資訊
阿新 • • 發佈:2018-11-10
1、本博文中程式碼是轉載內容,原文章地址如下:
https://blog.csdn.net/submit66/article/details/78631342?utm_source=blogxgwz1
2、只是在原文程式碼的基礎上稍作修改,添加了一些註釋及無關緊要的程式碼
3、本篇博文涉及知識點如下:
- ①建立類、建立函式
- ②建立新執行緒
- ③用瀏覽器檢查網頁元素
- ④使用BeautifulSoup獲取網頁內容
- ⑤儲存網頁文字內容到本地檔案
- ⑥下載圖片
- ⑦時間戳
4、程式碼功能為獲取“豆瓣電影top250”頁面的摘要資訊,詳細程式碼如下(執行環境:win7 + python3)
import requests
from bs4 import BeautifulSoup
import time
import os
import threading
'''
定義一個類,屬性包含圖片的序號、名稱以及下載的url
'''
class Picture:
def __init__(self,pic_num,pic_name,pic_url):
self.pic_name = pic_name
self.pic_url = pic_url
self.pic_num = pic_num
'''
下載圖片,因為他比較耗時,所以將其放在子執行緒中
'''
def download_picture(pic_list):
#設定圖片儲存的目錄,雙反斜槓\\表示轉義“\”,實際的作用相當於'douban\pic\'
file_dir = "douban\pic\\"
#如果目錄不存在,就建立它
if not os.path.isdir(file_dir):
os.makedirs(file_dir)
#下載圖片
for index in range(len(pic_list)):
try:
#獲取圖片列表的單個元素
pic_url = pic_list[index]
#設定圖片的名字,加上路徑是指在路徑下建立圖片
filename = file_dir +str(pic_url.pic_num) + '_' + pic_url.pic_name + ".jpg"
# "wb"表示以二進位制寫入檔案
# 此處".content"表示以二進位制形式返回資料,下載圖片及音訊時需用此方式
# 此處的timeout並不是指超過5秒沒下載完圖片就算超時,而是指5秒內伺服器沒有響應連線請求就超時
with open(filename,'wb') as f_open:
f_open.write(requests.get(pic_url.pic_url,timeout=5).content)
#因為要下載250個圖片,如果長時間等待,看不出程式正常執行,此處每下載10個圖片在終端就提示一次
if pic_url.pic_num % 10 == 0:
print("已下載%d張圖片" % (pic_url.pic_num))
except:
print("下載失敗!")
#pass表示不返回任何錯誤提示
pass
print("爬取耗時:",time.time().__float__() - cuttentTime.__float__(),'s')
# param 分頁網址的字尾,用於拼接
param = ''
# i 圖片下載的個數
i = 1
#時間戳,用於計算程式執行的時間
cuttentTime = time.time()
# pic_list 儲存圖片名字及圖片的下載地址
pic_list = []
while True:
base_url = 'https://movie.douban.com/top250' + param
my_response = requests.get(base_url,timeout = 5)
#若頁面返回的狀態碼不是200,則顯示錯誤
my_response.raise_for_status()
response_string = my_response.text
soup = BeautifulSoup(response_string,'lxml')
#所有的電影資訊都在class為grid_view的ol標籤中
ol_article = soup.find('ol',class_='grid_view')
#每部電影對應一個li
li_list = ol_article.find_all('li')
#獲取電影的資訊
for index in range(len(li_list)):
div_item_info = li_list[index].find('div',class_='info')
div_hd = div_item_info.find('div',class_='hd')
div_bd = div_item_info.find('div',class_='bd')
title_list = div_hd.find_all('span')
#獲取電影名
title_str = div_hd.find('span',class_='title').getText()
#獲取電影別名
if div_hd.find('span',class_='other'):
alias_title_str = div_hd.find('span',class_='other').getText().\
replace(' ','').replace(' ','').replace('/','',1)
#獲取導演、演員、上映年、電影型別等資訊
content_description_str = div_bd.p.getText().replace(' ','\t\t').\
replace(' ','').replace(' / ','/')
#獲取評價星級
rating_star = div_bd.div.find_all('span')[1].getText()
#獲取評論數量
comment_str = div_bd.div.find_all('span')[3].getText()
#獲取一句話影評
if div_bd.find('p',class_='quote'):
quote_str = div_bd.find('p',class_='quote').span.getText()
#將抓取的資訊存入本地文件
file_dir = "douban\\"
if not os.path.isdir(file_dir):
os.makedirs(file_dir)
filename = file_dir + "douban250.txt"
#此處的"encoding='utf-8'",以utf-8編碼建立開啟檔案,為防止寫入檔案編碼錯誤
with open(filename,'a',encoding='utf-8') as f_open:
f_open.write("\n第%d個電影--------------------------------------" % (i))
f_open.write("\n\n\t電影名稱:" + title_str)
f_open.write("\n\t電影別名:" + alias_title_str)
f_open.write("\n\t電影評星:" + rating_star)
f_open.write("\n\t評價數量:" + comment_str)
f_open.write("\n\t電影一句話總結:" + quote_str)
f_open.write("\n\t電影大致內容資訊:" + content_description_str)
#獲取圖片資訊
div_pic = li_list[index].find('div',class_='pic')
pic_list.append(Picture(i,div_pic.a.img.get('alt'),div_pic.a.img.get('src')))
i += 1
#獲取分頁資訊
div_paginator = soup.find('div',class_='paginator')
next_url = div_paginator.find('span',class_='next')
#如果沒有link則退出while迴圈,用來判斷已經到達最後一頁
if not next_url.link:
break
# 獲取link的某個屬性,可以使用get方法
param = next_url.link.get('href')
'''
在所有資料內容爬取完畢後開始一個新的執行緒下載圖片,這裡還非得用threading模組了,
因為它開啟的派生執行緒在執行時候,主執行緒不會退出,直至派生執行緒執行完畢
但是如果派生執行緒被設定為守護執行緒,即設定setDaemon為true的話,
主執行緒退出派生執行緒也就不執行了(但是這個不是我們想要的)
如果直接使用thread模組就會存在主執行緒提前退出派生執行緒無法執行完畢,導致下載失敗的情況
'''
#這裡我不明白原作者為什麼要開啟一個新執行緒去下載圖片,與直接批量下載圖片有什麼區別嗎,
# 此問題待以後學習更多執行緒相關的知識後再分析
try:
threa_download = threading.Thread(target=download_picture,args=(pic_list,))
threa_download.setDaemon(False)
threa_download.start()
except:
print('Error: unable to start thread')