學技術,從性趣開始

ETHANAIR發表於2018-07-09

為什麼這麼說?

因為我想學Python很久了,聽說它能做很多隻有你想不到,沒有它做不到的事。 然而事實很殘酷,我是懶癌晚期患者,一直只專注在iOS開發當中(儘管做的也不咋好)。但是看到身邊搞開發的朋友們都在努力去熟悉其他語言,我開始慌了。這時候我意識到我應該學習一門Objective-C & Swift之外的語言了。但前面說到了,我很懶,我不知道程式猿是不是都懶,學習一門新語言我必須給自己找到一個足夠充分的理由,才能驅動我去做這件事。直到有天我無意間進入了某AV網站,發現頁面清新脫俗,女優質量可以說很高了,就像下面這樣。 為了確保我不被Cop請去喝茶,圖片自行腦補吧

學技術,從性趣開始

然後我就萌生了一個寫Python爬蟲,抓取該網站所有AV Star作品.torrent的想法。 這個想法達到了驅動我學Python這件事的要求。緊接著我就開始埋頭苦幹了。第一次寫Python,我有點兒緊張,說的不對的地方請各位大神點選評論,留下您如杜蕾斯段子手般的文字,給我一個改過自新的機會。

第一步 - 安裝Python

這個我就不說了,請移步廖雪峰的官方網站-Python教程,廖老師已經講的很明瞭了。

第二步 - 去買一本書

由於我之前沒用過Python,所以我先是在京東買了一本《用Python寫網路爬蟲》,讓快遞小哥先幫我運著。

第三步 - 看幾個視訊教程

相比文字教程,我更喜歡看視訊教程,你想的沒錯,因為快,老師上課給你講的都是例題,這樣你下課才能通過例題去做習題,而不是上來就直接自己看例題,然後做習題。可能我笨吧。但這是我的學習方法。

我去慕課網逛了一圈,以x2的速度看完了兩套免費的Python爬蟲課程。 如果你之前像我一樣一點兒沒接觸過Python,那麼推薦你先看一下Python遇見資料採集。然後再看這個Python開發簡單爬蟲。不然你可能不太理解第二套課程中的設計模式。這是我踩的坑。

這兩個課程都不難,而且時間也很短,用x2的速度看足以讓你看懂爬蟲爬取網頁的一些套路。

第四步

根據兩套視訊課程的學習,相信你對爬取網頁的一些套路已經有所瞭解,然後我們就可以通過兩套視訊學到的知識,來進行coding

Coding Your First Python Project

我的開發環境是Python3

➜  ~ python3
Python 3.6.0 (default, Feb 11 2017, 01:31:31)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
複製程式碼

兩個教程本來講的是urllib + BeautifulSoup的方式進行爬取,但是我一開始就遇到了問題。 就是要爬取的網站要用科學上網的方式才能訪問,可是我用urllib中的request,無論我怎麼設定proxy,都沒有用。Google了很多,得到的答案大部分是用requests這個庫來進行請求。(如果哪位大神有解決方案,我懇請您告訴我,先謝謝了)

於是我就先用了requests來進行編寫

from bs4 import BeautifulSoup  # 引入 BeautifulSoup
import request                 # 引入 requests
import re                      # 引入 re
複製程式碼

然後我們定義一個url,還有一個headeruser-agent可以讓你簡單的偽裝成瀏覽器

url = 'https://xxx.com/actress' #這個地址是AV Star的列表

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
    "Upgrade-Insecure-Requests": "1"
}

複製程式碼

由於我用ss科學上網,所以這裡使用的是socks代理,地址你可以檢視你的網路偏好設定中的代理Tab

學技術,從性趣開始

proxies = {
            'http': 'socks5h://127.0.0.1:1080',
            'https': 'socks5h://127.0.0.1:1080'
    }
複製程式碼

緊接著我們就可以發起一個請求了

r = requests.get(url, proxies=proxies)   # 建立一個 requests 請求物件
soup = BeautifulSoup(r.content, 'html.parser', from_encoding='utf-8') # 建立一個 BeautifulSoup物件
複製程式碼

這個時候我們就可以去分析網頁的結構了

學技術,從性趣開始
箭頭從上到下依次是

  • 該Star主頁在網站中的地址
  • 圖片連結
  • Star的名字

我們還知道,列表中每個item的class="card",我們就可以用soup物件對我們要的資料進行取出了

cardList = soup.find_all('div', class_="card") # 取出所有class="card"的內容
複製程式碼

然後我們對cardList進行遍歷

starId = 0   # 初始化一個star id,方便我們對接下來資料庫的寫入
for card in cardList:

    sibling_soup = card

    starId = starId + 1 # starId自增

    # < p class ="card-header-title is-centered" > Star的名字在這個p標籤裡,我們用.find進行查詢
    starName = sibling_soup.find('p', class_="card-header-title is-centered").get_text().strip()
    # .get_text()是獲取這個p標籤裡的text(不包含其他標籤),然後用.strip()對字串進行去除前後空格的操作
    
    # 然後我們用re.compile去匹配sibling_soup物件中符合 /actress/ 的標籤
    # 這裡我偷了懶,因為網頁中每個card裡面只有一個a標籤內容中含有 /actress/ ,所以我這樣寫了
    starPage = sibling_soup.find('a', href=re.compile(r"/actress/"))['href']
    # ['href']是拿到這個a標籤中的連結
    # 拼接一下網站的域名
    starPage = "https://xxx.com" + starPage

    # < img class ="card-image" src="https://xxx.com/mono/movie/adult/mide558/mide558pl.jpg" >
    # 同樣的方式去拿到圖片的地址
    starImgUrl = sibling_soup.find('img', class_="card-image")['src']
複製程式碼

拿到了我們要的資料之後,就可以插入到資料庫中了(關於資料庫的安裝與相關操作,可以觀看上面推薦視訊1)

# 開啟本地資料庫
staronnection = pymysql.connect(host='localhost', 
                                    user='root',
                                    db='Python',
                                    charset='utf8mb4')
    try:

        with staronnection.cursor() as cursor:
            sql = "insert into `AvStar`(`id`,`name`,`url`,`thumb`) values(%s, %s, %s, %s)"
            cursor.execute(sql, (starId, starName, starPage, starImgUrl))
            staronnection.commit()
    # 插入我們前面拿到的資料

    # 關閉資料庫
    finally:
        staronnection.close()
複製程式碼

到現在,我們算是完成了60%了,接下來就是進入其中某個Star頁面中一探究竟了。看一下頁面結構,分析下我們需要的資料

學技術,從性趣開始
圖片中的紅框自上而下是

  • 該作品的海報
  • 該作品的番號
  • 該作品.torrent檔案的下載地址

ojbk,我們就要這些就行了

我們先只查詢每個Star作品列表的前三頁,

# 查詢該Star的作品列表
    for num in [1, 2, 3]:

        newUrl = "%s?page=%d" % (starPage, num) # 拼接一下請求地址
        newResp = requests.get(newUrl, proxies=proxies) # 發起一個新請求
        newSoup = BeautifulSoup(newResp.content, 'html.parser', from_encoding='utf-8') # 建立一個新的BeautifulSoup物件

        # <div class="columns">
        avList = newSoup.find_all('div', class_="columns") # 拿到列表中每個作品對應的標籤內容

        # 存種子下載連結
        for av in avList:

            avSoup = av
            # 拿到圖片連結
            avThumb = avSoup.find('img', class_="image")["src"]
            
            # <h5 class="title is-4 is-spaced"/> 拿到番號
            avCode = avSoup.find('a', href=re.compile(r"/torrent/")).get_text().strip()
            
            # 拿到下載連結
            avAddress = avSoup.find('a', class_="button is-primary is-fullwidth")["href"]
            
            # 拼接下載連結
            avAddress = "https://xxx.com" + avAddress
            
            # 開啟資料庫,注意到這時我們在資料庫中已經有一張AvStar的表用來儲存Star的基礎資訊
            # 這裡我們要新建一個表,用來儲存每部作品的資訊
            connection = pymysql.connect(host='localhost',
                                         user='root',
                                         db='Python',
                                         charset='utf8mb4')
            try:

                with connection.cursor() as cursor:
                    sql = "insert into `AvAddress`(`star_id`,`thumb`, `address`) values(%s, %s, %s)"
                    cursor.execute(sql, (starId, avThumb, avAddress))
                    connection.commit()


            finally:
                connection.close()
                # 關閉資料庫
            
            # 這裡我們發起一個請求 傳入.torrent的下載地址
            fileResp = requests.get(avAddress, proxies=proxies)
            
            # 點選頁面中的下載按鈕,通過'檢查'進行分析,見下圖
            # 我們拿到Response Headers中的'Content-Disposition'
            # 自定義一個名字
            # 最後將檔案寫入到工程資料夾中
            if fileResp.headers.get('Content-Disposition'):
                # filename = "xxx.com_mide540_2.torrent
                filename = "xxx.com_" + avCode + ".torrent"
                open(filename, 'wb').write(fileResp.content)
                print("is downloaded" + filename + "onej" + "av" + ".com")
                
複製程式碼

學技術,從性趣開始

Run 一下吧

至此,程式碼部分已經完成,我們run一下程式吧(想想還有點兒小激動)

➜  PythonProject git:(master) ✗ python3 xxx
複製程式碼

緊接著,我的工程目錄下就新增了這麼多檔案,之後你再用迅雷開啟.torrent,進行下載就行了。

學技術,從性趣開始

總結

  1. 先分析你要抓取的網頁地址、頁面結構,檢視其規律性,找到其中的套路
  2. 用最簡單的方式拿到你想要的東西(這大概是Python這門語言的精髓所在了吧)

要解決的問題

  1. 插入資料庫前應該判斷一下資料庫中有沒有當前要插入的資料,如果有,就不插入。
  2. 我覺得應該加入一個sleep什麼的,這樣每抓一個頁面就停一下,可以有效避免被封ip,當然了,小站可能沒做這麼多,但是大站貌似都會有反爬蟲機制吧。
  3. 總感覺for的效率不是很高,我這裡for3次,時間複雜度為,感覺應該開執行緒去跑,比如每個Star開一個執行緒去跑,這樣會不會更好一些,但我還沒學習到那裡。接下來可能就哪裡不會點哪裡了。
  4. 最好是下載完.torrent之後自動開啟下載器進行下載,這樣白天上班時,家裡的電腦跑著,晚上到家一看,電腦的硬碟爆了。哈哈哈哈

PS: 聰明的大神總能在程式碼中找到他們想要的,比如說:網址

`你離的越近看,你看到的東西越少` 
                --- 驚天魔盜團
複製程式碼

相關文章