需求:爬取豆瓣電影top250的排名、電影名稱、評分、評論人數和一句話影評
環境:python3.6.5
准備工作:
豆瓣電影top250(第1頁)網址:https://movie.douban.com/top250?start=0 或者 https://movie.douban.com/top250
每頁展示25個電影,一共10張翻頁
第2頁:https://movie.douban.com/top250?start=25&filter=
第3頁:https://movie.douban.com/top250?start=50&filter=
……
最后一頁:https://movie.douban.com/top250?start=225&filter=
由此可見,除了首頁代碼其他9頁(相對首頁增加了一些字符串)以25遞增
查看每頁的html代碼:
在瀏覽器空白區域點擊“查看源代碼”(不同的瀏覽器可能起的名字不一樣),找到所需要的內容。
快速定位html有效信息的方法:
例如排名第一的電影是《肖申克的救贖》,在html源碼中搜索(ctrl+F)這個名字(不要加書名號),快速定位大致位置,如下圖
仔細研究html代碼:
所有影片存放在ol列表中,每一部影片在一個li中,需要提取的信息在不同的標簽中,如下圖所示
代碼邏輯為:查找ol→li→各個標簽
需要用到的第三方庫:
from bs4 import BeautifulSoup as bs from urllib import request
讀取html源碼(以首頁為例)
1 h="https://movie.douban.com/top250" 2 resp = request.urlopen(h) 3 html_data = resp.read().decode('utf-8') 4 soup = bs(html_data,'lxml') 5 #print(soup.prettify())
第5行的soup.prettify()輸出的比較好看,但是有可能更改一些並列標簽的前后位置,用這個輸出只是看起來更人性化一些
查找ol標簽,獲取本頁面上25部電影
通過class名稱,因為這個class是唯一命名的,因此無需find_all,只需要find(這個是查找第一個)
1 movieList = soup.find('ol',attrs={'class':"grid_view"})
在ol內查找li標簽,無class和id,只需標簽名即可
1 movie = movieList.find_all('li')#獲取每一個li(每個li是一個電影),以數組方式
返回結果是一位數組,每個元素是li標簽
在每一個li標簽內提取有用信息
1 for i in range(0,25): 2 name = movie[i].find('span',class_="title").string#獲得影片名稱 3 score = movie[i].find('span',class_="rating_num").string#獲得影片評分 4 num = movie[i].find('div',class_="star").find_all('span')[-1].string.strip('人評價')#獲得影片評價人數 5 quote = movie[i].find('span',class_="inq")#獲得影片短評
.string和get_text()在本代碼中顯示結果一樣(有些代碼中返回顯示也是不同的),但是返回類型不同
注意第4行獲取評價人數時,span標簽內無class和id等,只能先把div中所有的信息提取(返回結果是一位數組),人數在數組中最后一個,通過數組方法[-1]提取這個標簽,通過string提取標簽內內容,再用strip字符串方法去掉“人評價”這幾個字
還有一點需要注意是,有幾部影片是沒有短評的(通過運行程序的結果才能看到,返回的是None),如果需要顯示的更加人性化一些,添加以下語句:
1 if quote is None: 2 quote = "暫無" 3 else: 4 quote = quote.string
查找所有信息:不要想着把10頁的html先拼接成一個html處理,這樣的的html進行soup時只能提取到第一個<html>標簽內的,也就是說只能查到第一頁的信息。因此總體思路還是遍歷每一頁的電影信息,然后將結果拼接成數組。如果只是print出來或者逐行寫入歧途文件的話無需整合所有影片
寫入txt文件,提取出的結果是二維數組
1 #將數組movieData250寫入文件txt 2 import codecs 3 s ="—————————豆瓣電影top250——————————\r\n" 4 f = codecs.open("豆瓣電影top250.txt",'w','utf-8') 5 f.write(s) 6 7 for i in movieData250: 8 f.write(str(i)+'\r\n') #\r\n為換行符 9 f.close()
源代碼:
1 #豆瓣電影前250信息,寫入txt文件 2 3 from bs4 import BeautifulSoup as bs 4 from urllib import request 5 k = 0 6 n = 1 7 movieData250 = [] 8 9 #讀取每一個網頁25個電影信息 10 def info25(): 11 movieData = [] 12 for i in range(0,25): 13 name = movie[i].find('span',class_="title").string#獲得影片名稱 14 score = movie[i].find('span',class_="rating_num").string#獲得影片評分 15 num = movie[i].find('div',class_="star").find_all('span')[-1].string.strip('人評價')#獲得影片評價人數 16 quote = movie[i].find('span',class_="inq")#獲得影片短評 17 if quote is None: 18 quote = "暫無" 19 else: 20 quote = quote.string 21 #movieData[i] = [i+1,name,score,num,quote] 22 movieData.append([i+1+k,name,score,num,quote]) 23 #print(movieData) 24 return movieData 25 #movieData250 = movieData250 + movieData 26 27 28 29 while(k == 0): 30 h="https://movie.douban.com/top250" 31 resp = request.urlopen(h) 32 html_data = resp.read().decode('utf-8') 33 soup = bs(html_data,'lxml') 34 #print(soup.prettify()) 35 #movieList=soup.find('ol')#尋找第一個ol標簽,得到所有電影 36 #movieList=soup.find('ol',class_="grid_view")#以下兩種方法均可 37 movieList = soup.find('ol',attrs={'class':"grid_view"}) 38 movie = movieList.find_all('li')#獲取每一個li(每個li是一個電影),以數組方式 39 movieData250 +=info25() 40 k += 25 41 42 while(k<250): 43 44 h = "https://movie.douban.com/top250?start=" + str(k) + "&filter=" 45 resp=request.urlopen(h) 46 html_data=resp.read().decode('utf-8') 47 soup=bs(html_data,'lxml') 48 #print(soup.prettify()) 49 #movieList=soup.find('ol')#尋找第一個ol標簽,得到所有電影 50 #movieList=soup.find('ol',class_="grid_view")#以下兩種方法均可 51 movieList=soup.find('ol',attrs={'class':"grid_view"}) 52 movie=movieList.find_all('li')#獲取每一個li(每個li是一個電影),以數組方式 53 movieData250 += info25() 54 k+=25 55 56 print(movieData250) 57 58 59 #將數組movieData250寫入文件txt 60 import codecs 61 s ="—————————豆瓣電影top250——————————\r\n" 62 f = codecs.open("豆瓣電影top250.txt",'w','utf-8') 63 f.write(s) 64 65 for i in movieData250: 66 f.write(str(i)+'\r\n') #\r\n為換行符 67 f.close()
輸出的txt:
顯示結果不是很友好~~~