首先我們開始要分析一下,下載種子我們需要哪幾步:
- 獲取所有電影頁的訪問地址
- 獲取電影頁源碼
- 提取出下載地址
- 將下載地址保存
首先第一步,我們來分析一下電影天堂網站的結構,發現他跟我們的古詩文網還是非常類似的,全站靜網結構,不需要登錄,頁面有全新的地址,這對於初學來講是非常容易上手的;接下來我們以國內電影(https://www.ygdy8.net/html/gndy/china/index.html)爲例,先把所有電影詳情頁的地址獲取到:
我們發現我們需要的地址<a href="***" class="ulink">以鏈接的形式存在,且所有的地址都是這種形式,那麼我們可以用正則表達式直接匹配所有符合這種樣式的文本,最後把地址做一個拼接就好了;
我們發現亂碼了,這是因爲什麼,我們之前在爬取古詩文網的時候是沒有這種問題的,這是因爲網站的文字編碼不一樣,在我們python3裏面默認使用的是utf-8,我們看下古詩文網和電影天堂的編碼格式分別是什麼:
我們發現古詩文網的編碼格式就是“utf-8”,而電影天堂的編碼格式是“gb2312”,編碼格式不一樣,當然會亂碼了,所以我們需要設置一下編碼格式:
這下就正常了,總結一下:如果發現獲取的源碼亂碼了,到網頁源碼中搜索一下“charset”,看一下網頁的編碼是什麼
ok,現在源碼我們已經有了,接下來就是獲取詳情頁的地址了:
import requests
import re # 導入正則表達式庫
url = 'https://www.ygdy8.net/html/gndy/china/index.html'
result = requests.get(url)
result.encoding = 'gb2312'
html = result.text
reg = '<a href="(.*?)" class="ulink">' # 匹配的規則
href = re.findall(reg,html) # 在源碼中匹配所有滿足其規則的文本
print(href)
# 輸出結果:
# ['/html/gndy/dyzz/20191204/59430.html', '/html/gndy/jddy/20191203/59421.html', '/html/gndy/jddy/20191203/59420.html', '/html/gndy/dyzz/20191129/59405.html', '/html/gndy/dyzz/20191127/59402.html', '/html/gndy/dyzz/20191126/59401.html', '/html/gndy/dyzz/20191125/59398.html', '/html/gndy/dyzz/20191124/59394.html', '/html/gndy/jddy/20191118/59382.html', '/html/gndy/dyzz/20191115/59376.html', '/html/gndy/dyzz/20191113/59363.html', '/html/gndy/jddy/20191110/59357.html', '/html/gndy/jddy/20191110/59356.html', '/html/gndy/jddy/20191109/59352.html', '/html/gndy/jddy/20191109/59351.html', '/html/gndy/dyzz/20191107/59345.html', '/html/gndy/dyzz/20191101/59301.html', '/html/gndy/dyzz/20191027/59287.html', '/html/gndy/jddy/20191027/59282.html', '/html/gndy/dyzz/20191026/59279.html', '/html/gndy/dyzz/20191024/59273.html', '/html/gndy/jddy/20191019/59253.html', '/html/gndy/dyzz/20191017/59249.html', '/html/gndy/dyzz/20191016/59241.html', '/html/gndy/jddy/20191015/59236.html']
那麼就有兩個問題出現了:
- 爲什麼匹配的規則是<a href="(.*?)" class="ulink">?
我們回顧一下上面我們需要的地址的那部分字段是怎麼樣的
我們發現,非常相似,就是中間的網址被替換成了 (.*?) - 其中的 (.*?) 是什麼意思?
那這個 (.*?) 就是未知字符了,他的準確意思是,任意長度的任意字符,這個是正則部分的內容,可以自行百度,這個基本可以說是萬能用法,可以先把這個掌握,後面再慢慢學習其他的
我們現在已經把詳情頁的地址獲取到了,下一步就是訪問詳情頁,然後把磁力鏈接地址獲取到了:
其實就是一樣的操作,這邊就不贅述了,我們發現上面的代碼幾乎有一半都是重複的,獲取源碼、正則匹配的部分可以直接寫成方法:
我們現在已經把一個頁面所有電影的磁力鏈接獲取到了,接下來我們就需要將這些信息存儲起來,當然不要忘記片名,不然哪個是哪個就傻傻分不清了:
從上面的代碼我們可以看到,已經將一個頁面的磁力鏈接和片名對應,並且保存了起來,這裏如果對zip()和csv讀寫相關有疑問的話,可以自行百度,也可以查看Python3基礎篇——讀寫csv文件和python3基礎篇——列表的高級用法兩篇文章;
接下來我們就需要把所有的頁面都處理了,通過網址我們可以發現就是最後的數字變化,那麼我們只需要將網址進行一個拼接就好了
SOS:驚奇的發現,當我們爬取到24頁之後,後面沒有磁力鏈接地址了,那麼我們只好轉戰下載ftp的地址,同樣也是可以下載的:
import requests
import re
import csv
def get_html(url): # 獲取頁面源碼
url = url
result = requests.get(url) # 發出訪問請求
result.encoding = 'gb2312' # 設置編碼格式,搜索頁面源碼charset
html = result.text # 獲取源碼
return html
title = [] # 存儲標題
data = [] # 存儲下載地址
n = 1 # 頁碼
status = 0 # 重新訪問次數
while n < 123: # 這裏我們使用while循環,處理訪問出錯的頁面
try: # 異常處理很重要,不然可能最後一頁前破功了
# 直接簡單粗暴,拼接地址
url = 'https://www.ygdy8.net/html/gndy/china/list_4_{}.html'.format(str(n))
html = get_html(url)
print(url) # 將地址打印出來,可以知道現在搜索到哪一頁了
reg = '<a href="(.*?)" class="ulink">' # 匹配詳情頁地址規則
href = re.findall(reg,html)
for h in href: # 遍歷頁面所有電影詳情頁
info_url = 'https://www.ygdy8.net/' + h
info_html = get_html(info_url)
try:
data_reg = '<a href="(.*?)">ftp://'
title_reg = '<font color=#07519a>(.*?)</font>'
title_tmp = re.findall(title_reg, info_html)[0]
data.append(re.findall(data_reg,info_html)[0]) # 將下載地址添加到列表
title.append(title_tmp) # 注意,先地址再標題,不然如果頁面沒有下載地址,標題添加進去就不對應了
except:
print('{}獲取失敗'.format(title_tmp)) # 打印那部電影出錯了
n += 1 # 翻頁
status = 0 # 重新訪問次數情況
except: # 如果頁面訪問出錯
if status < 4: # 重新訪問三次
status += 1 # 次數加1
print('訪問出錯,重新訪問第{}遍'.format(status)) # 輸出錯誤次數信息
else:
n += 1 # 如果重新訪問三次還是訪問不到,那麼直接翻頁
status = 0
all_data = list(zip(title, data)) # 將標題和地址打包
with open('國內電影.csv', 'w', newline='', encoding='utf-8-sig') as f: # 寫入文件
writer = csv.writer(f)
writer.writerows(all_data)