這是我第一個Python爬蟲項目,Python基礎太差,花了好久,下面詳細的解釋一下這個項目,因為是第一個項目,可能邏輯有些混亂,代碼也不夠簡潔,歡迎指正,哈哈
之前看到好多文章關于爬取網頁圖片的,于是就找到了圖蟲網,爬取上面的星(xiao)空(jie)圖(jie)
先說明一下,爬蟲的基本流程
- 構造url,然后請求此url
- 根據返回的數據,分析響應的內容,找到圖片的鏈接
- 請求圖片的鏈接,然后將它保存在本地
下面看一下要爬取的網頁
圖蟲網
我們選擇一個標簽來查看,在瀏覽器中按住F12,調出開發者web開發工具箱
我們隨意點開一個圖集,開始分析一下
將url里面的數字放到第一張圖片里面搜索一下,看一下是否能夠查到
可以搜索到,所以考慮可以請求這個網頁,然后獲取這個網頁中所有圖集的url,然后在每個圖集的url的網頁里面找到每一張圖片的鏈接,最后再下載
但是這個網頁會在用用戶不斷的向下滾動時,不斷地加載新的內容,這樣就不好辦了,就像下面這樣(web開發工具里面選擇網絡)
可以在上面圖片畫紅線的地方,發現一個小小的規律,就是這個鏈接,
https://tuchong.com/rest/tags/少女/posts?page=2&count=20&order=weekly
多此加載之后發現只有page=2這個數字2變化,于是有了轉機,打開這個鏈接,會看到這個東西
這是一個json數據,不太了解這個,不過查資料后發現可以用Python中的json庫進行檢索。就是json.loads()將json編碼的字符串轉化為Python數據結構
進一步分析這個數據,可以發現在postList下面的,所有url字典對應的都是一個圖集的url
好了,第一步搞定
然后就是每個圖集中的圖片的處理,在一個圖集中,和前面一樣的分析方法,
但是發現了一個比較有有意思的事情,就是在點擊刷新的時候,頁面會發現變化,如下圖(我也不太清楚為什么,不是很了解前端的知識。)
我們就用下面的圖來分析
審查一下圖片我們就可以發現了
這個鏈接在原來的html源代碼中,這樣就可以用正則表達式來匹配出了。
到此為止,找到了每個標簽下面的每個圖集的鏈接,還有每個圖集下面的每張圖片的鏈接,思路清晰了,就可以來編寫代碼了
import os
import re
import json
import requests
import time
import urllib.parse
import random
import traceback
#定義要爬取的標簽和正在爬取的頁數
def UserUrl(theme,pagenum):
url = "https://tuchong.com/rest/tags/%(theme)s/posts?page=%(pagenum)s&count=20&order=weekly" % {'theme': urllib.parse.quote(theme), 'pagenum': pagenum}
#print(url)
return url
#利用requests使用get方法請求url,使用User-Agent是為了防止被反爬,這樣使得我們的爬取行為更像人的行為
def GetHtmltext(url):
head = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"
}
try:
r = requests.get(url, headers=head, timeout=30)
r.raise_for_status() #如果返回的狀態碼不是200,就到except中
return r
except:
pass
#定義獲取一個pagenum頁面中的所有圖集的URL鏈接的函數
def PictureFatherUrl(user_url):
try:
raw_data = GetHtmltext(user_url)
j_raw_data = json.loads(raw_data.text) #將獲取的網頁轉化為Python數據結構
# print(j_raw_data)
father_url = [] #將每個圖集的url定義為father_url的一個列表
for i in j_raw_data['postList']: #解析出的j_raw_data是一個多重字典,在這里先將postList字典的內容取出來
father_url.append(i['url']) #然后再取出鍵為“url”的值
# print(father_url)
# print(len(father_url))
return father_url
except:
return
#定義獲取一個圖集中所有圖片的url鏈接
def PictureUrl(url):
try:
html = GetHtmltext(url)
#利用正則表達式來匹配
url_list = list(re.findall('<img id="image\d+" class="multi-photo-image" src="([a-zA-z]+://[^\s]*)" alt="">', html.text))
return url_list
except:
pass
#定義一個圖集中所有圖片的下載
def Download(url):
url_list = PictureUrl(url)
for i in url_list:
r = GetHtmltext(i)
file_name = os.path.join(save_path, i.split('/')[-1])
# file_name = str(i)
with open(file_name, 'wb') as f:
f.write(r.content)
f.close()
time.sleep(random.uniform(0.3, 0.5)) #為防止被反爬,在這里random了0.3-0.5的數,然后在下載一張圖片后,sleep一下
print('save %s' % file_name)
#定義主函數
if __name__ == '__main__':
theme = input("你選擇的標簽(如果你不知道有什么標簽,去https://tuchong.com/explore/去看看有什么標簽吧,輸入不存在的標簽無法下載哦):")
pagenum_all = int(input("你要爬取的頁數(不要太貪心哦,數字太大會被封IP的):"))
save_path = os.path.join(theme)
m = 0
if not os.path.exists(save_path):
os.makedirs(save_path)
print("我知道你沒有創建保存路徑,我把文件存在和此腳本同樣的路徑下的叫做“ %s ”的文件夾下面了" % theme)
for i in range(1, pagenum_all+1):
n = 0
m += 1
print("正在下載第%d頁,一共%d頁" % (m, pagenum_all))
user_url = UserUrl(theme, i)
father_url = PictureFatherUrl(user_url)
for j in father_url:
n += 1
print("正在下載第%d套圖,一共%d套圖" % (n, len(father_url)))
Download(j)
time.sleep(random.randint(6, 10)) #同樣為了反爬,也random了6-10之間的數,更真實的模擬人的操作