爬蟲 網站開發實例:電影票比價網

注:一篇去年的舊文,發現沒在知乎發過,過來補個檔。有個小問題是項目中淘票票的網頁反爬提升且變動較多,目前暫不可用了。

時常有同學會問我類似的問題:我已經學完了 Python 基礎,也照着例子寫過一點爬蟲代碼 / 瞭解過 django 的入門項目 / 看過數據分析的教程……然後就不知道要做什麼了。接下來應該如何繼續提升編程能力呢

我的答案很簡單:

做項目

不要把“項目”想象得太複雜,覺得一定是那種收錢開發的才能稱作項目(如果有這種項目當然會更好)。對於剛剛跨入編程世界的你來說,任何一個小項目都是好的開始。你所需要的,就是一雙發現問題的眼睛。生活中工作中的一些小事情小麻煩,多想一步,是不是可以寫一小段代碼來解決。

一開始,或許你的解決方案很笨拙,很複雜,本來5分鐘就能搞定的事情,你寫代碼卻花了一個小時。但對你來說,此時的目的並不只是解決問題,而是這個過程本身。在折騰的過程中,你的經驗纔會增長。這是你單純看教程所無法達到的,再好的教程也替代不了動手。(有時候會有人評論說,這功能直接用xxx就可以了,幹嘛還要自己寫代碼。對此我不做評價,因爲我知道他不是來學編程的。)

我們編程教室也陸續提供了一些項目案例。你可以參考我們的示例代碼,或者更好的是,自己去思考一個解決方案並實現。我們的案例不少都放在了網站 lab.crossincode.com 上演示,歡迎大家去瀏覽。內容會持續更新,可留意我們微信公衆號和知乎專欄裏的文章。


今天介紹的這個項目就源自生活中的一個場景:買電影票

當你打算週末出門看場電影的時候,就必然面臨三個終極問題:

  1. 看什麼?
  2. 什麼時候看?
  3. 去哪兒看?

通常你只需要打開常用的購票App,選一部最近口碑不錯的片子,去熟悉的影院看看有哪些場次就可以了。但有時你也會發現,同樣一部電影,不遠的兩家影院,價格就差很多,不同的購票App也會因爲促銷活動之類有不同的優惠力度,一張票可能會相差幾十元。但如果每次都去幾個App把最近的排片和價格都瀏覽一遍,那也太麻煩了。於是就有了我們這個小項目:

電影票比價網

在我們這個網頁上,會展示出當前熱映的電影。進入每部電影,選擇城市區域影院日期,就可以看到最近的排片時間和不同渠道的價格。目前,我們是從糯米淘票票時光網三個渠道獲取價格來做演示。(注:項目中淘票票現已失效)

實現技術

本項目是對爬蟲和Web網站的綜合運用,適合已經有掌握python基礎,並且對此有一些瞭解的同學作爲練手項目。涉及到模塊主要是:

  • Django(1.10)
  • requests
  • bs4
  • python-Levenshtein(用來匹配不同渠道的影院信息)

代碼結構

項目主要有三塊:

  1. douban_movie
    使用豆瓣 api 每日更新上映的影片列表。
  2. movie_tickets
    項目的核心部分,用來處理影院信息和排名信息的抓取。
  3. django
    項目本身是一個網站,整體是在 django 的框架之中。

開發思路

  1. 使用爬蟲爬取各電影票網站所有的電影院鏈接,作爲基本的數據保存下來
  2. 使用豆瓣 API 獲取當日上映的電影信息,並每天更新
  3. django 顯示電影信息,提供給用戶選擇電影院的接口
  4. 將影片和影院信息發送到 django 後臺進行查詢,爬取對應的排片信息顯示給用戶

代碼片段

# 獲取淘票票某地區某電影院某影片價格# 
1. 根據查詢條件獲取影院 id# 
2. 根據影院 id 獲取該影院正在上映電影# 
3. 獲取 查詢電影的排片時間表鏈接# 
4. 拿到價格
def get_movie_tickets(self, *args):
    assert len(args) == 4, 'not enough parameters \n type in -h for help'
    movie_name = args[3]
    mt = TaoppDt()
    cinema_url = mt.search(*args[:3])
    assert cinema_url, '未查詢到該電影院'
    pattern = re.compile(r'cinemaId=(\d )')
    cinemaid = re.findall(pattern, cinema_url)[0]
    film_url = 'https://dianying.taobao.com/cinemaDetailSchedule.htm?cinemaId='   str(cinemaid)
    content = self.rq.req_url(film_url)
    assert content, '請求失敗,請檢查 /utils/req.py 中 req_url 函數是否工作正常'
    soup = bs4.BeautifulSoup(content, 'lxml')
    soup_film = soup.find('a', text=re.compile(movie_name))
    assert soup_film, '未查詢到該電影'
    film_param = soup_film['data-param']
    return self._get_ticket_info(film_param)

其他說明

  1. 項目爲了有一個較好的交互效果,在頁面上用到了不少 Ajax 請求。這需要有一定的前端 js 基礎。對網頁前端不熟悉的同學可暫且略過,重點關注後端實現。
  2. 不同渠道對於同一家影院的名稱很可能有出入,因此這裏使用了 python-Levenshtein 來對文本進行匹配。
  3. 代碼裏在抓取時有用到我們的另一個項目:IP代理池(參見 Crossin:聽說你好不容易寫了個爬蟲,結果沒抓幾個就被封了?)。但因爲服務器資源有限,有時拿不到可用的代理。各位自己電腦上運行代碼時,可嘗試把 requests 的 proxies 參數去除。
  4. 作爲一個演示項目,必然存在一些bug(當然商業項目也不可能沒有bug),加上爬蟲的程序極有可能因爲對方網站更新而失效。所以如果遇到問題,歡迎大家給我們報錯。

代碼下載

完整的代碼詳細代碼說明已上傳 Github,獲取下載地址請在公衆號(Crossin的編程教室)裏回覆 電影票


════

其他文章及回答:

學編程:如何自學Python | 新手引導 | 一圖學Python

開發案例:智能防擋彈幕 | 紅包提醒 | 流浪地球

歡迎搜索及關注:Crossin的編程教室

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章