小白學 Python 爬蟲(24):2019 豆瓣電影排行

小白學 Python 爬蟲(24):2019 豆瓣電影排行

人生苦短,我用 Python

前文傳送門:

小白學 Python 爬蟲(1):開篇

小白學 Python 爬蟲(2):前置準備(一)基本類庫的安裝

小白學 Python 爬蟲(3):前置準備(二)Linux基礎入門

小白學 Python 爬蟲(4):前置準備(三)Docker基礎入門

小白學 Python 爬蟲(5):前置準備(四)數據庫基礎

小白學 Python 爬蟲(6):前置準備(五)爬蟲框架的安裝

小白學 Python 爬蟲(7):HTTP 基礎

小白學 Python 爬蟲(8):網頁基礎

小白學 Python 爬蟲(9):爬蟲基礎

小白學 Python 爬蟲(10):Session 和 Cookies

小白學 Python 爬蟲(11):urllib 基礎使用(一)

小白學 Python 爬蟲(12):urllib 基礎使用(二)

小白學 Python 爬蟲(13):urllib 基礎使用(三)

小白學 Python 爬蟲(14):urllib 基礎使用(四)

小白學 Python 爬蟲(15):urllib 基礎使用(五)

小白學 Python 爬蟲(16):urllib 實戰之爬取妹子圖

小白學 Python 爬蟲(17):Requests 基礎使用

小白學 Python 爬蟲(18):Requests 進階操作

小白學 Python 爬蟲(19):Xpath 基操

小白學 Python 爬蟲(20):Xpath 進階

小白學 Python 爬蟲(21):解析庫 Beautiful Soup(上)

小白學 Python 爬蟲(22):解析庫 Beautiful Soup(下)

小白學 Python 爬蟲(23):解析庫 pyquery 入門

引言

從本篇的標題各位同學應該已經猜到了,本篇又到了實戰環節~~~

2019 已經快過完了,按照本文推送的時間預估,到 2020 應該還有十來天的時間,又到了各個公司出各種 2019 榜單的時間,小編這裡呢,就先幫豆瓣搞一個 2019 電影評分排行榜,希望豆瓣官方看到不要打我。

鄭重聲明: 本文僅限用作學習等目的。

分析

還是先看一下我們要爬取的頁面:

小白學 Python 爬蟲(24):2019 豆瓣電影排行

鏈接:

<code>https://movie.douban.com/explore#!

type

=movie&tag=%E7%

83

%AD%E9%

97

%A8&

sort

=

time

&page_limit=

20

&page_start=

0

/<code>

思維敏捷的同學看著上面這個鏈接可能就已經發現了什麼,對的,這個鏈接上已經有分頁信息了。

page_limit 應該是一頁的元素, page_start 應該是這一頁開始的一個序號。

我們往下翻一下頁面,看看下面有沒有下一頁之類的按鈕,翻幾頁看下地址欄的變化是否和我們推測的一致。

小白學 Python 爬蟲(24):2019 豆瓣電影排行

emmmmmmmmm

小編猜錯了,這裡不是下一頁,是加載更多,不過問題不大,一個意思,先點一下我們看下地址欄:

<code>https://movie.douban.com/explore#!

type

=movie&tag=%E7%

83

%AD%E9%

97

%A8&

sort

=

time

&page_limit=

20

&page_start=

20

/<code>

和前面一個地址作對比可以發現,只有最後的 page_start 參數有變化,說明我們剛才上面的猜測沒有問題。

加載更多多點幾次,可以發現,這裡的電影是可以一直往後排的,可以加載到 2018 年的數據:

小白學 Python 爬蟲(24):2019 豆瓣電影排行

emmmmmmmmm,有點尷尬,這個數據竟然手動翻出來了,理論上是應該程序自己判斷的。

這裡的懸浮層上已經顯示了我們想要的數據,接下來的問題是,我們如何獲得這個懸浮層上的數據,直接從 DOM 節點來取可以麼?

顯然是不行的,不信可以自己動手試試,每個電影的懸浮層其實都是同一個 DOM 節點,只是裡面填充的數據不同,顯然這個 DOM 節點中的數據是鼠標挪上去的時候才動態加載出來的。

那麼我們從哪裡能看到加載數據的來源呢?

如果上一篇實戰有仔細看實操過的同學應該已經想到了, Chrome 瀏覽器開發者模式中的 Network 標籤。

沒錯,就是這裡,我們看一下:

小白學 Python 爬蟲(24):2019 豆瓣電影排行

首先選擇 Network 標籤,然後在下面的標籤上選擇 XHR 。然後鼠標在不同的電影上移動,可以看到鼠標每次移到一張圖片上,就會有一個請求,我們看一下這個請求的響應信息:

<code>{

"r"

:

0

,

"subject"

:{

"episodes_count"

:

""

,

"star"

:

"40"

,

"blacklisted"

:

"available"

,

"title"

:

"我身體裡的那個傢伙 내안의 그놈‎ (2019)"

,

"url"

:

"https:\/\/movie.douban.com\/subject\/27088750\/"

,

"collection_status"

:

""

,

"rate"

:

"7.2"

,

"short_comment"

:{

"content"

:

"男主真的他媽帥 但是我真的接受不了和羅美蘭打k "

,

"author"

:

"SOUL"

},

"is_tv"

:

false

,

"subtype"

:

"Movie"

,

"directors"

:[

"姜孝鎮"

],

"actors"

:[

"鄭振永"

,

"樸聖雄"

,

"羅美蘭"

,

"李垂珉"

,

"李俊赫"

,

"金光奎"

,

"閔智雅"

,

"尹敬浩"

,

"金賢穆"

,

"樸慶惠"

,

"趙賢榮"

,

"尹頌雅"

,

"智燦"

,

"金凡振 "

,

"鄭元昌"

,

"孫光業"

,

"黃仁俊"

,

"Dae-han Kim"

],

"duration"

:

"122分鐘"

,

"region"

:

"韓國"

,

"playable"

:

false

,

"id"

:

"27088750"

,

"types"

:[

"劇情"

,

"喜劇"

],

"release_year"

:

"2019"

}} /<code>

那麼我們剩下要關心的就是這個請求的地址了,先看下這個請求的地址:

<code>

https

: /<code>

這裡看起來好像只有最後一個 subject_id 參數是變化的,其他的都是定死的,多看幾個請求檢驗下我們的推測,小編這裡就不檢驗了,免得嫌棄說小編水內容。

還有一個問題,最後這個 subject_id 的數據從哪裡來,好像沒見過的,小編憑藉自己多年豐富的開發經驗,猜測這個數據應該是在頁面的上的。我們接著看下這個電影的頁面 DOM 結構。

小白學 Python 爬蟲(24):2019 豆瓣電影排行

看到了沒,這裡的數據是來源於 DOM 結構上的 data-id 屬性。

PS:更新一件事情,一件異常尷尬的事情,小編偶然發現,點擊加載更多的時候,實際上是對應了一個 API 接口,這個接口的訪問地址如下:

<code>https:

//movie

.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&

sort

=

time

&page_limit=

20

&page_start=

20

/<code>

這個在 NetWork 中有看到,如下圖:

小白學 Python 爬蟲(24):2019 豆瓣電影排行

從圖中可以看到,這裡直接返回了 JSON 數據,並且這個 JSON 數據返回後,順便還修改了地址欄的數據。

這裡得到的數據如下:

<code>{
    

"subjects"

:[ {

"rate"

:

"6.7"

,

"cover_x"

:

1382

,

"title"

:

"在無愛之森吶喊"

,

"url"

:

"https://movie.douban.com/subject/30337760/"

,

"playable"

:

false

,

"cover"

:

"https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2571542101.jpg"

,

"id"

:

"30337760"

,

"cover_y"

:

2048

,

"is_new"

:

false

} ] } /<code>

因為整體數據有 20 條,太長了放不下,小編這裡僅保留了一條數據。

編碼

有了上面的分析,其實寫代碼就已經很簡單了,我們所有需要用到的數據都可以直接從 API 接口中直接獲取到 JSON 的數據。

屢一下思路,首先我們從

<code>https:

//movie

.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&

sort

=

time

&page_limit=

20

&page_start=

0

/<code>

這個鏈接中直接獲取電影的相關數據,這裡對我們有用的數據是 id ,獲取到這個 id 後,再從

<code>

https

: /<code>

這個鏈接中獲取到電影的詳情數據,用上面得到的 id 替換這裡的 subject_id 。

好像沒頁面 DOM 解析啥事兒了,哎,真的是一次失敗的選題,下次再也不選豆瓣了。

代碼內容有些簡單,小編直接貼出來吧,數據還是在 Mysql 中開了一張表做存放:

<code>

import

requests

import

pymysql

def

connect

()

:

conn = pymysql.connect(host=

'localhost'

, port=

3306

, user=

'root'

, password=

'password'

, database=

'test'

, charset=

'utf8mb4'

) cursor = conn.cursor()

return

{

"conn"

: conn,

"cursor"

: cursor} connection = connect() conn, cursor = connection[

'conn'

], connection[

'cursor'

] sql_insert =

"insert into douban2019(id, title, rate, short_comment, duration, subtype, region, release_year, create_date) values (%(id)s, %(title)s, %(rate)s, %(short_comment)s, %(duration)s, %(subtype)s, %(region)s, %(release_year)s, now())"

headers = {

'User-Agent'

:

'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'

} flag =

True

def

get_movie_list

(page_start)

:

r = requests.get(

'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=time&page_limit=20&page_start='

+ str(page_start), headers = headers)

for

item

in

r.json()[

'subjects'

]: get_movie_info(item[

'id'

])

def

get_movie_info

(subject_id)

:

r = requests.get(

'https://movie.douban.com/j/subject_abstract?subject_id='

+ str(subject_id), headers=headers) subject = r.json()[

'subject'

]

if

subject[

'release_year'

] !=

'2019'

:

global

flag flag =

False

return

print(subject) insert_data = {

"id"

: subject[

'id'

],

"title"

: subject[

'title'

],

"rate"

: subject[

'rate'

],

"short_comment"

: subject[

'short_comment'

][

'content'

],

"duration"

: subject[

'duration'

],

"subtype"

: subject[

'subtype'

],

"region"

: subject[

'region'

],

"release_year"

: subject[

'release_year'

] } cursor.execute(sql_insert, insert_data) conn.commit() print(subject[

'title'

],

'寫入完成'

)

def

main

()

:

num =

0

while

(flag): get_movie_list(num) num +=

20

if

__name__ ==

'__main__'

: main() /<code>

小結

最後小編做了一下簡單的統計,截止目前, 2019 豆瓣電影共計 312 部,評分超過 8.0 分的共計 37 部,超過 8.5 分的共計 14 部,超過 9.0 分的只有 1 部。

下表為評分超過 8.0 分的,還有沒看過的小夥伴可以抓緊時間看一下咯~~

名稱評分愛爾蘭人 The Irishman‎ (2019)9.1銀河英雄傳說 Die Neue These 星亂 第1章 銀河英雄伝説 Die Neue These 星亂 第1章‎ (2019)8.9小丑 Joker‎ (2019)8.8婚姻故事 Marriage Story‎ (2019)8.8玩具總動員4 Toy Story 4‎ (2019)8.7寄生蟲 기생충‎ (2019)8.7代號基亞斯:復活的魯路修 コードギアス 復活のルルーシュ‎ (2019)8.782年生的金智英 82년생 김지영‎ (2019)8.7克勞斯:聖誕節的秘密 Klaus‎ (2019)8.6痛苦與榮耀 Dolor y gloria‎ (2019)8.6青春期豬頭少年不做懷夢少女的夢 青春ブタ野郎はゆめみる少女の夢を見ない‎ (2019)8.6復仇者聯盟4:終局之戰 Avengers: Endgame‎ (2019)8.5哪吒之魔童降世‎ (2019)8.5普羅米亞 プロメア‎ (2019)8.5少年的你‎ (2019)8.4少年泰坦出擊大戰少年泰坦 Teen Titans Go! vs Teen Titans‎ (2019)8.4悲慘世界 Les misérables‎ (2019)8.4我的一級兄弟 나의 특별한 형제‎ (2019)8.3燃燒女子的肖像 Portrait de la jeune fille en feu‎ (2019)8.3再見鍾情 Mon inconnue‎ (2019)8.3我在雨中等你 The Art of Racing in the Rain‎ (2019)8.2羅小黑戰記‎ (2019)8.2行騙天下JP:浪漫篇 コンフィデンスマンJP‎ (2019)8.2阿松 劇場版 劇場版 えいがのおそ松さん‎ (2019)8.2蠟筆小新:新婚旅行颶風之遺失的野原廣志 映畫クレヨンしんちゃん 新婚旅行ハリケーン ~失われたひろし~‎ (2019)8.2馭風男孩 The Boy Who Harnessed the Wind‎ (2019)8.1對不起,我們錯過了你 Sorry We Missed You‎ (2019)8.1續命之徒:絕命毒師電影 El Camino: A Breaking Bad Movie‎ (2019)8.1我失去了身體 J'ai perdu mon corps‎ (2019)8.1最初的夢想 Chhichhore‎ (2019)8.1千子2 センコロール コネクト‎ (2019)8.0地久天長‎ (2019)8.0金髮男子 Un rubio‎ (2019)8.0心理測量者SS2:第一衛士 PSYCHO-PASS サイコパス Sinners of the System Case.2「First Guardian」‎ (2019)8.0漫長的告別 長いお別れ‎ (2019)8.0我的喜馬拉雅‎ (2019)8.0小委託人 어린 의뢰인‎ (2019)8.0

示例代碼

本系列的所有代碼小編都會放在代碼管理倉庫 Github 和 Gitee 上,方便大家取用。

示例代碼-Github

示例代碼-Gitee


分享到:


相關文章: