由于畢業設計推薦系統需要大量電影資訊資料,從豆瓣電影爬取了一萬多條電影資料,記錄一下第一次爬資料,同時感謝豆瓣電影平台提供的資料。
爬取思想:豆瓣選電影頁面用的是JS動态渲染,用谷歌浏覽器檢視點選加載時發送的URL,解析拼接為新的URL,在Scrapy架構中以該URL為入口,每次擷取到20個電影資料,再分别通路20個電影的URL位址擷取到詳細的電影資料,用Xpath解析html頁面。
具體步驟如下:
1.解析拼接url
通路豆瓣頁面點選加載更多,谷歌檢視此時背景發現它發送了一個請求:
https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=&start=20
通過這個URL請求可以擷取到20條JSON格式的電影資料,每次通過對start參數自增20擷取到資料。
2.擷取資料
請求url擷取到如下的JSON格式資料:
解析擷取JSON格式資料:
dicts=json.loads(response.body)['data']
循環20個電影清單通路每個電影詳情頁的url擷取HTML頁面
movie_url=dict['url']
movie_html=requests.get(movie_url)
root = etree.HTML(movie_html.content)
movies=root.xpath('//div[@id="content"]')
用Xpath解析HTML頁面元素擷取到資料,并且給item
movie_id=movie_url[33:-1]
movie_title=each.xpath('.//h1/span[1]/text()')
movie_title = ",".join(movie_title)
release_year=each.xpath('.//h1/span[2]/text()')
release_year = ",".join(release_year).split(')')[0].split('(')[1]
movie_img=each.xpath('.//div[@id="mainpic"]/a/img/@src')
movie_img = ",".join(movie_img)
director=each.xpath('.//div[@id="info"]/span[1]/span[2]/a/text()')
director=",".join(director)
screenwriter=each.xpath('.//div[@id="info"]/span[2]/span[2]/a/text()')
screenwriter = ",".join(screenwriter)
starring=each.xpath('.//div[@id="info"]//a[@rel="v:starring"]/text()')
starring = ",".join(starring)
type=each.xpath('.//div[@id="info"]/span[@property="v:genre"]/text()')
type = ",".join(type)
production_country=each.xpath('.//div[@id="info"]/text()[preceding-sibling::span[text()="制片國家/地區:"]][following-sibling::br]')[0]
language=each.xpath('.//div[@id="info"]/text()[preceding-sibling::span[text()="語言:"]][following-sibling::br]')[0]
release_time=each.xpath('.//div[@id="info"]/span[@property="v:initialReleaseDate"]/text()')
release_time = ",".join(release_time)
length=each.xpath('.//div[@id="info"]/span[@property="v:runtime"]/text()')
length = ",".join(length)
url=movie_url
imdb_link=each.xpath('.//div[@id="info"]/a/@href')
imdb_link = ",".join(imdb_link)
alias=each.xpath('.//div[@id="info"]/text()[preceding-sibling::span[text()="又名:"]][following-sibling::br]')
if alias:
alias=alias[0]
score=each.xpath('.//div[@id="interest_sectl"]/div[1]/div[2]/strong/text()')
score = ",".join(score)
synopsis=each.xpath('.//div[@id="link-report"]/span/text()')
synopsis = ",".join(synopsis).replace(" ","").replace("\u3000","")
重構URL位址,再進行擷取電影資料
url = response.url
url = url.split('=')
url[-1] = str(int(url[-1])+20)
next_url = '='.join(url)
yield scrapy.Request(next_url,callback=self.parse,dont_filter=True)
3.将資料存到Mysql資料庫
class DoubanmoviePipeline(object):
def __init__(self,dbpool):
self.dbpool=dbpool
@classmethod
def from_settings(cls,settings):
dbparams=dict(
host=settings['MYSQL_HOST'],
db=settings['MYSQL_DBNAME'],
user=settings['MYSQL_USER'],
password=settings['MYSQL_PASSWORD'],
charset='utf8',
cursorclass=pymysql.cursors.DictCursor,
use_unicode=False,
)
dbpool=adbapi.ConnectionPool('pymysql',**dbparams)
return cls(dbpool)
def process_item(self, item, spider):
asynitem = copy.deepcopy(item)
if isinstance(item,DoubanmovieItem):
query=self.dbpool.runInteraction(self._conditional_insert_movie,asynitem)
query.addErrback(self._handle_error,asynitem,spider)
elif isinstance(item,MovieRcmdItem):
query=self.dbpool.runInteraction(self._conditional_insert_moviercmd,asynitem)
query.addErrback(self._handle_error,asynitem,spider)
return asynitem
def _conditional_insert_movie(self,tx,item):
sql="insert into movie(movie_id,movie_title,movie_img,director,screenwriter,starring,type,production_country,language,release_time,length,release_year,url,imdb_link,alias,score,synopsis) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
params=(item['movie_id'], item['movie_title'],item['movie_img'],item['director'],item['screenwriter'],item['starring'],item['type'], item['production_country'],item['language'],item['release_time'],item['length'],item['release_year'],item['url'], item['imdb_link'],item['alias'],item['score'],item['synopsis'])
tx.execute(sql,params)
注意對資料進行深拷貝,否則爬取速度太快已爬取的資料還沒存入資料庫,後面的資料就已經覆寫掉前面的資料。
4.反爬蟲政策
- 在setting裡面禁用cookie
- 使用IP代理,購買IP代理池(這裡買的是阿布雲的IP代理)或者網上找IP代理池
- 随機UserAgent頭
最後爬取了一萬多條資料,如果隻是做推薦系統的話,不需要太多的國家等這麼多詳細資訊,網上也有很多已經爬取好的資料,我這裡是做的Web推薦系統,是以需要更多詳細的電影資料才自己按需求爬取的資料。另外,如果隻是需要少量資料的話可以使用一些爬蟲軟體,比如八爪魚、火車頭、後羿采集器。我個人比較喜好後羿采集器,感覺定制規則友善很多。