為什麼這麼說?
因為我想學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
,還有一個header
,user-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
,進行下載就行了。
總結
- 先分析你要抓取的網頁地址、頁面結構,檢視其規律性,找到其中的套路
- 用最簡單的方式拿到你想要的東西(這大概是Python這門語言的精髓所在了吧)
要解決的問題
- 插入資料庫前應該判斷一下資料庫中有沒有當前要插入的資料,如果有,就不插入。
- 我覺得應該加入一個
sleep
什麼的,這樣每抓一個頁面就停一下,可以有效避免被封ip,當然了,小站可能沒做這麼多,但是大站貌似都會有反爬蟲機制吧。 - 總感覺for的效率不是很高,我這裡
for
了3
次,時間複雜度為n³
,感覺應該開執行緒去跑,比如每個Star開一個執行緒去跑,這樣會不會更好一些,但我還沒學習到那裡。接下來可能就哪裡不會點哪裡了。 - 最好是下載完
.torrent
之後自動開啟下載器進行下載,這樣白天上班時,家裡的電腦跑著,晚上到家一看,電腦的硬碟爆了。哈哈哈哈
PS: 聰明的大神總能在程式碼中找到他們想要的,比如說:網址
`你離的越近看,你看到的東西越少`
--- 驚天魔盜團
複製程式碼