? 學(xué)習(xí)了《簡明Python教程》项棠,然后想著實(shí)戰(zhàn)一下拉队,搜索了一些資料秆乳,然后對豆瓣電影排行250進(jìn)行了一個(gè)抓取般妙,后續(xù)還會對數(shù)據(jù)進(jìn)行一些分析纪铺。
? 這篇文章主要是對抓取豆瓣電影top250過程的一個(gè)梳理,方便日后自己查閱碟渺,也希望可以方便到有需要的人鲜锚。
? 下面是整個(gè)抓取過程的思維導(dǎo)圖:
1. 生成URL信息
? 首先觀察豆瓣電影TOP250的網(wǎng)頁地址,多點(diǎn)開幾頁苫拍,就能發(fā)現(xiàn)規(guī)律芜繁。每一頁都是展示了25個(gè)電影。
2. 分析網(wǎng)頁標(biāo)簽
? 這個(gè)就是對網(wǎng)頁html文件的解析了怯疤,可以先在網(wǎng)頁中瀏覽目標(biāo)信息浆洗,然后在網(wǎng)頁的源碼中通過搜索查找到相應(yīng)的標(biāo)簽。最后一定要搞清楚定位每一個(gè)目標(biāo)信息標(biāo)簽的方式集峦。
? 我在這是采用的是BeautifulSoup對html進(jìn)行的解析伏社。
3. 請求網(wǎng)頁數(shù)據(jù)
? 我是使用urllib.request中的urlopen()方法對網(wǎng)頁進(jìn)行請求的。
urlopen(url).read().decode('utf-8')
? urlopen(url)獲取到的是HTTPResponse對象塔淤,然后調(diào)用read()方法獲得網(wǎng)頁的字節(jié)數(shù)據(jù)摘昌,字節(jié)數(shù)據(jù)沒法直接處理,所以最后調(diào)用decode('utf-8')方法將獲取的字節(jié)對象編碼成文本字符串(string)
4. 存儲信息
? 先把數(shù)據(jù)生成pandas庫的DataFrame對象高蜂,然后調(diào)用其to_csv()方法將數(shù)據(jù)存儲到csv文件中聪黎,非常的方便。
完整的代碼
? 算是自己完成了第一個(gè)小的爬蟲程序备恤,以后會在此基礎(chǔ)上不斷的擴(kuò)展與完善稿饰。下面是獲取豆瓣電影TOP250的Python完整代碼。
# encoding=utf-8
from collections import defaultdict
from urllib.request import urlopen
from bs4 import BeautifulSoup
import pandas as pd
import time
import re
class DoubanMovieTop250:
# 生成url和相應(yīng)存儲最終數(shù)據(jù)的容器
def __init__(self):
self.top250_urls = ['https://movie.douban.com/top250?start={0}&filter='.format(i * 25) for i in range(10)]
self.data = defaultdict(list)
self.columns = ['title', 'link', 'score', 'score_cnt', 'top_no', 'directors', 'writers', 'actors', 'types',
'edit_location', 'language', 'dates', 'play_location', 'length', 'rating_per',
'betters', 'had_seen', 'want_see', 'tags', 'review', 'ask', 'discussion']
self.df=None
def get_info(self):
for url in self.top250_urls:
# 將獲取的網(wǎng)頁封裝成BeautifulSoup
print(url)
html = urlopen(url).read().decode('utf-8')
bsobj = BeautifulSoup(html)
# 開始解析網(wǎng)頁中的數(shù)據(jù)
main = bsobj.find('ol', {'class': 'grid_view'})
# 標(biāo)題及鏈接信息
title_obj = main.findAll('div', {'class': 'hd'})
titles = [ i.find('span', {'class': 'title'}).text for i in title_obj]
links = [ i.find('a')['href'] for i in title_obj]
# 評分信息
score_obj = main.findAll('div', {'class': 'star'})
scores = [i.find('span', {'class': 'rating_num', 'property': 'v:average'}).text for i in score_obj]
score_cnts = [ i.findAll('span')[-1].text for i in score_obj]
# 將解析到的數(shù)據(jù)存入到容器中
for title, link, score, score_cnt in zip(titles, links, scores, score_cnts):
self.data[title].extend([title, link, score, score_cnt])
# 解析更多露泊、更詳細(xì)的信息
more_data = self.get_more_info(link)
self.data[title].extend(more_data)
print(self.data[title])
print(len(self.data))
time.sleep(1)
def get_more_info(self, link):
html = urlopen(link).read().decode('utf-8')
bsobj = BeautifulSoup(html)
# 榜單排名 top_no
top_no = bsobj.find('span', {'class': 'top250-no'}).text
# 導(dǎo)演 directors
main = bsobj.find('div', {'id': 'info'})
directors = [i.text for i in main.findAll('a', {'rel': 'v:directedBy'})]
# 編劇 writers 可能沒有編劇
try:
writers = [i.text for i in main.findAll('span', {'class': 'attrs'})[1].findAll('a')]
except Exception as ex:
writers = []
print(ex)
# 主演 actors 可能沒有主演
try:
actors_obj = main.findAll('a', {'rel': 'v:starring'})
actors = [i.text for i in actors_obj]
except Exception as ex:
actors = []
print(ex)
# 類型 types
types_obj = main.findAll('span', {'property': 'v:genre'})
types = [i.text for i in types_obj]
# 制片地區(qū) edit_location
pattern = re.compile('地區(qū):(.*)\n語言', re.S)
edit_location = re.findall(pattern, main.text)[0]
# 語言 language
pattern2 = re.compile('語言:(.*)\n上映日期', re.S)
language = re.findall(pattern2, main.text)[0]
# 上映日期和地區(qū) dates play_location
date_boj = main.findAll('span', {'property': 'v:initialReleaseDate'})
dates = [i['content'].split('(')[0] for i in date_boj]
play_location = [i['content'].split('(')[1] for i in date_boj]
# 片長 length
length = main.find('span', {'property': 'v:runtime'})['content']
# 5星到1星的比例 rating_per 一共是5個(gè)數(shù)字
rating_per = [i.text for i in bsobj.findAll('span', {'class': 'rating_per'})]
# 好于 betters
better_obj = bsobj.find('div', {'class': 'rating_betterthan'}).findAll('a')
betters = [i.text for i in better_obj]
# 想看/看過 had_seen want_see
fit_obj = bsobj.find('div', {'class': 'subject-others-interests-ft'})
had_seen = fit_obj.find('a').text[:-3]
want_see = fit_obj.findAll('a')[1].text[:-3]
# 標(biāo)簽 tags
tags = [i.text for i in bsobj.find('div', {'class': 'tags-body'}).findAll('a')]
# 短評 review (有多少個(gè)短評)
review = bsobj.find('div', {'id': 'comments-section'}).find('h2').find('a').text
# 問題 ask (有多少個(gè)問題)
ask = bsobj.find('div', {'id': 'askmatrix'}).find('a').text.strip()
# 討論 discussion (有多少個(gè)討論)
discussion = bsobj.find('p', {'class': 'pl', 'align':'right'}).find('a').text.strip().split('(')[1][2:-2]
more_data=[top_no, directors, writers, actors, types, edit_location, language, dates, play_location, length, rating_per, betters, had_seen, want_see,tags, review, ask, discussion]
return more_data
# 存儲數(shù)據(jù)到csv文件
def dump_data(self):
data = []
for title, value in self.data.items():
data.append(value)
self.df=pd.DataFrame(data, columns=self.columns)
self.df.to_csv('exercise_douban_movie_Top250.csv')
if __name__ == '__main__':
douban = DoubanMovieTop250()
douban.get_info()
douban.dump_data()