1. 程式人生 > >2-6-1 應用案例:爬取豆瓣 TOP250 電影資訊並存儲(版本:py3)——學習筆記

2-6-1 應用案例:爬取豆瓣 TOP250 電影資訊並存儲(版本:py3)——學習筆記

爬取電影名稱、連結並寫入檔案

import urllib.request as urlrequest
from bs4 import BeautifulSoup
import time #休息時間
import random #為了時間隨機

top250_url="https://movie.douban.com/top250?start={}&filter="

with open('C:/Users/feng_jlin/Desktop/douban_250.txt','w') as outputfile:
    
     for i in range(10):
            start = i*25
            url_visit = top250_url.format(start)
            crawl_content = urlrequest.urlopen(url_visit).read()
            http_content = crawl_content.decode('utf8')
            soup = BeautifulSoup(http_content,'html.parser')
            
            all_item_divs = soup.find_all(class_='item')
            
            for each_item_div in all_item_divs:
                    pic_div=each_item_div.find(class_='pic')
                    item_href=pic_div.find('a')['href']
                    item_name=pic_div.find('img')['alt']

                    outputfile.write('{}  {}\n'.format(item_href,item_name))
                    print('{}   {}\n'.format(item_href,item_name))

現在把他修改為,需要爬去電影詳情,若無則從TOP250頁面爬取相關資料

# -*- coding:utf-8 -*

import urllib.request as urlrequest
from bs4 import BeautifulSoup
import time #休息時間
import random #為了時間隨機
import bs4   #注意點1:引入模組

#item_href 連結
#item_name 名稱
#all_attrs_divs 主演
#movie_type_join 電影型別
#score_soup_divs 電影評分

top250_url = "https://movie.douban.com/top250?start={}&filter=" #top250的連結
movie_url = "https://movie.douban.com/subject/{}/" #movie進去詳情頁面

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'} #表頭防封,360瀏覽器

with open('C:/Users/feng_jlin/Desktop/douban_250.txt','w',encoding='utf8') as outputfile: #開啟本地儲存CSV檔案
    
     for i in range(10): #一共250個,一頁25個,共10頁,這個則是迴圈10頁
            start = i*25 #設定放在連結{}中的start
            url_visit = top250_url.format(start)
            
            req_url_visit = urlrequest.Request(url=url_visit, headers=headers) #將防封表頭寫入連結
            crawl_content = urlrequest.urlopen(req_url_visit).read() #讀取連結
            
            http_content = crawl_content.decode('utf8') #因為有中文,把格式改為utf8
            soup = BeautifulSoup(http_content,'html.parser') #用beautifulsoup解析網頁
            
            all_item_divs = soup.find_all(class_='item') #找到所有class=item,形成all_item_divs的列表
            
            for each_item_div in all_item_divs: #進行列表迴圈
                
                pic_div = each_item_div.find(class_='pic') #找到pic
                item_href = pic_div.find('a')['href'] #找到a中的href連結
                item_name=pic_div.find('img')['alt'] #找到電影名稱
                    
                https, blank , web, subject, doubanID ,other = item_href.split('/') #分割/得到豆瓣ID
                    
                movie_url_visit = movie_url.format(doubanID) #movie詳情頁連結補充完整
                try:
                    req_movie_url_visit = urlrequest.Request(url=movie_url_visit, headers=headers) #將防封表頭寫入連結
                    movie_crawl_content = urlrequest.urlopen(req_movie_url_visit).read() #讀取連結
                    
                    movie_http_content = movie_crawl_content.decode('utf8') #因為有中文,把格式改為utf8
                    movie_soup = BeautifulSoup(movie_http_content,'html.parser') #用beautifulsoup解析網頁
                    
                    #獲取主演
                    all_actor_divs = movie_soup.find(class_='actor')
                    if isinstance(all_actor_divs,bs4.element.Tag) == True: #上面actor類別為空的話下一步會出錯,所以用isinstance過濾空TAG,避免錯誤
                        all_attrs_divs = all_actor_divs.find(class_='attrs').get_text() #可以用split('/')分出列表,但本次不需要 
                    else:
                        all_attrs_divs = "空"
                    
                    type_soup_divs = movie_soup.find_all(property="v:genre") #獲取電影型別
                    movie_type = [] #重置
                    for i in range(0,len(type_soup_divs)):
                        movie_type.append(type_soup_divs[i].get_text()) #獲取get_text()文字,去除tag,放到一個新的列表中
                    movie_type_join = '/'.join(movie_type) #join連線列表中的元素
                    
                    score_soup_divs = movie_soup.find(class_="ll rating_num").get_text() #獲取電影評分
                    
                    outputfile.write('{}  {}  {}  {}  {}\n'.format(item_href,item_name,movie_type_join,score_soup_divs,all_attrs_divs))
                    print('{}  {}  {}  {}  {}\n'.format(item_href,item_name,movie_type_join,score_soup_divs,all_attrs_divs))
                    
                    time_interval = random .uniform(1,5) #隨機1-5秒停止
                    time.sleep(time_interval)  # wait some time, trying to avoid google forbidden (of crawler)
                        
                except urlrequest.HTTPError as err:
                    other_attrs_divs = re.findall('主演: (.*?)<br/>',str(each_item_div),re.S) #正則抓取TOP250頁面的主演
                    other_type_join = re.findall('主演: .*?<br/>.*?/.*?/.(.*?)\n.*?</p>',str(each_item_div),re.S) #正則抓取TOP250頁面的型別
                    other_score_div = re.findall('<span class="rating_num" property="v:average">(.*?)</span>',str(each_item_div),re.S) #正則抓取TOP250頁面的電影評分
                
                    
                    if not len(other_attrs_divs): #以防有些內容為空,無法爬取
                        other_attrs_divs.append('空')
                    print(other_attrs_divs)
                    
                    if not len(other_type_join):
                        other_type_join.append('空')
                    print(other_type_join)
    
                    if not len(other_score_div):
                        other_score_div.append('空')
                    print(other_score_div)
                    
                    outputfile.write('{}  {}  {}  {}  {}\n'.format(item_href,item_name,other_type_join[0],other_score_div[0],other_attrs_divs[0]))
                    print('{}  {}  {}  {}  {}\n'.format(item_href,item_name,other_type_join[0],other_score_div[0],other_attrs_divs[0]))
                    continue #防中間爬取的20頁為空,判斷若有錯不跳出,繼續

outputfile.close()
print('OK')