1. 背景
??百度貼吧上有許多美圖头滔,幾張或十幾張圖片手動下載還可以鲤氢,但幾十張狠持,上百張就比較麻煩恳啥,故希望編個程序批量下載百度貼吧的原圖。由于python爬蟲代碼簡單某残,故利用python來編程窘茁。
2. 準備
2.1 貼吧組成
??現(xiàn)在使用孫允珠吧舉例妈嘹。一個貼吧由一個個帖子組成背犯,帖子中包含圖片坏瘩。故理論上下載原圖的一般方法是:先打開貼吧主頁,再打開帖子漠魏,然后點擊圖片使其原圖顯示倔矾,最后下載圖片。
2.2 分析網(wǎng)頁url
貼吧主頁:http://tieba.baidu.com/f?kw=%CB%EF%D4%CA%D6%E9&fr=ala0&loc=rec
貼吧帖子:http://tieba.baidu.com/p/6383722178
原圖顯示:http://tieba.baidu.com/photo/p?kw=%E5%AD%99%E5%85%81%E7%8F%A0&ie=utf-8&flux=1&tid=6383722178&pic_id=4254484e251f95ca67a500d0c6177f3e660952e7&pn=1&fp=2&see_lz=1
分析結(jié)果:
1. 貼吧主頁中 “kw=%CB%EF%D4%CA%D6%E9” 是gb2312格式的UrlEncode編碼柱锹,“kw=%E5%AD%99%E5%85%81%E7%8F%A0” 是utf-8格式的UrlEncode編碼哪自,它們解碼結(jié)果是:孫允珠。
解碼網(wǎng)站:站長工具UrlEncode編碼/解碼
2. 貼吧帖子中 “6383722178” 是帖子編號禁熏。
3. 原圖顯示中 “pic_id=4254484e251f95ca67a500d0c6177f3e660952e7” 是圖片編號提陶。
4. 由原圖顯示的url可知,打開1張原圖需要 “kw=%E5%AD%99%E5%85%81%E7%8F%A0” 匹层、“tid=6383722178” 和 “pic_id=4254484e251f95ca67a500d0c6177f3e660952e7”
2.3 分析關(guān)鍵信息
- 打開貼吧主頁。點擊右上角設(shè)置圖標->更多工具->開發(fā)者工具(谷歌瀏覽器)锌蓄,或網(wǎng)頁鼠標右鍵點擊->檢查即可看到源碼升筏。
- Ctrl+F查找帖子編號 “6383722178” ,找到關(guān)鍵代碼瘸爽,提取出正則表達式您访。若提取內(nèi)容不同,所需的正則表達式需要自己修改剪决,不懂可以參考Python3 正則表達式灵汪。
注意:瀏覽器上看到的關(guān)鍵代碼和程序獲取的關(guān)鍵代碼是不同的。
程序獲取的關(guān)鍵代碼:
<li class=" j_thread_list clearfix" data-field='{"id":6383722178,"author_name":"lovedovelyonly","author_nickname":null,"author_portrait":"tb.1.d0fa6477.jIFXO-fqudlDDQVl2lym9g","first_post_id":128733834249,"reply_num":26,"is_bakan":null,"vid":"","is_good":true,"is_top":null,"is_protal":null,"is_membertop":null,"is_multi_forum":null,"frs_tpoint":null}' data-tid='6383722178' data-thread-type="0" data-floor='6''>
程序所需的正則表達式:
r1 = r"data-tid='([0-9]+)' data-thread-type" # 正則表達式
- 同樣打開貼吧首頁的1個帖子柑潦,Ctrl+F查找圖片編號 “4254484e251f95ca67a500d0c6177f3e660952e7”享言,獲取關(guān)鍵代碼,提取出正則表達式渗鬼。
程序獲取的關(guān)鍵代碼:
<img class="BDE_Image" pic_type="0" width="560" height="560" src="http://imgsrc.baidu.com/forum/w%3D580/sign=61a7dc9d0546f21fc9345e5bc6256b31/4254484e251f95ca67a500d0c6177f3e660952e7.jpg" size="555815" >
程序所需的正則表達式:
r2 = r'src="http://imgsrc.baidu.com/(.*?)\.jpg"' # 正則表達式
- 打開原圖顯示url的源碼览露,找出可下載原圖的地址。
可下載原圖的地址:
http://imgsrc.baidu.com/forum/pic/item/4254484e251f95ca67a500d0c6177f3e660952e7.jpg
三譬胎、處理流程
??從上面的下載地址可知差牛,下載原圖需要知道 “4254484e251f95ca67a500d0c6177f3e660952e7” 即圖片編號命锄。故批量下載圖片時,只需給定貼吧首頁的url偏化,由首頁url的源碼找出帖子編號脐恩,再由帖子編號讀取帖子源碼,從而獲取圖片編號侦讨。最后由圖片編號組成原圖下載地址驶冒,通過其下載圖片。
四搭伤、源代碼
from urllib import request # 下載圖片
import re # 正則表達式
import os # 創(chuàng)建文件夾
from tqdm import trange # 進度條
# 讀取主頁源碼
url1 = "http://tieba.baidu.com/f?kw=%CB%EF%D4%CA%D6%E9&fr=ala0&loc=rec" # 貼吧首頁的網(wǎng)址
html = request.urlopen(url1, timeout=5) # 讀取網(wǎng)頁源碼
code = html.read().decode("UTF_8")
"""
file = open("1.html", "w", encoding='UTF-8') # 保存源碼
file.write(str(code))
file.close
print(code)
"""
# 提取帖子編號
r1 = r"data-tid='([0-9]+)' data-thread-type" # 正則表達式
c1 = re.compile(r1) # 根據(jù)正則表達式創(chuàng)建模式對象
f1 = re.findall(c1, code) # 匹配結(jié)果
# 提取帖子名稱
r2 = r'href="/p/[0-9]+" title="(.*?)"' # 正則表達式
c2 = re.compile(r2) # 根據(jù)正則表達式創(chuàng)建模式對象
title = re.findall(c2, code) # 匹配結(jié)果
i = 0
# 創(chuàng)建Image文件夾
if not os.path.exists("Image"):
os.mkdir("Image")
for tid in f1:
i = i + 1
# 讀取帖子源碼
url3 = 'http://tieba.baidu.com/p/' + tid # 帖子地址 'http://tieba.baidu.com/p/6383722178'
html3 = request.urlopen(url3, timeout=5) # 讀取網(wǎng)頁源碼
code3 = html3.read().decode("UTF_8")
# 提取圖片編號
r3 = r'src="http://imgsrc.baidu.com/(.*?)\.jpg"' # 正則表達式
c3 = re.compile(r3) # 根據(jù)正則表達式創(chuàng)建模式對象
f3 = re.findall(c3, code3) # 匹配結(jié)果
# 以該帖子的名稱創(chuàng)建文件夾
dir1 = "Image//" + title[i] + "(共" + str(len(f3)) + "張)//"
if not os.path.exists(dir1):
os.mkdir(dir1) # 創(chuàng)建帖子文件夾
with trange(len(f3)) as bar: # 進度條
for j in bar:
# 下載圖片并保存
s = f3[j].split("/")
pic_id = s[len(s) - 1]
# 圖片下載地址'http://imgsrc.baidu.com/forum/pic/item/4254484e251f95ca67a500d0c6177f3e660952e7.jpg'
url4 = 'http://imgsrc.baidu.com/forum/pic/item/' + pic_id + '.jpg'
f = open(dir1 + str(j) + ".jpg", 'wb')
f.write((request.urlopen(url4, timeout=5)).read())
f.close()
# 打印進度信息
bar.set_description(str(i) + ". " + title[i] + "(共" + str(len(f3)) + "張)")
print("貼吧首頁下載完成只怎。")
五、遇到的問題
問題1:點擊程序運行怜俐,但程序一直卡住身堡,既不報錯,又沒有結(jié)果拍鲤。
原因:經(jīng)調(diào)試發(fā)現(xiàn)程序一直卡住code = html.read()贴谎,所以程序應(yīng)加上超時處理和異常處理。如此程序會正常報錯季稳。
報錯程序:
from urllib import request
html = urllib.request.urlopen(url)
code = html.read()
code = code.decode("UTF_8")
改正后程序
from urllib import request, error
try:
html = request.urlopen(url, timeout=3)
code = html.read()
code = code.decode("UTF_8")
except error.URLError as e:
print(e.reason)
問題2:點擊程序運行擅这,發(fā)出超時錯誤。
原因:這可能是網(wǎng)絡(luò)連接不佳或者網(wǎng)站發(fā)現(xiàn)是爬蟲程序而禁止訪問景鼠,推薦博客python urllib.request的5個基本程序仲翎,使用異常處理,User_Agent和IP代理運行測試一下是否可以讀取url的源碼铛漓。
問題3:百度貼吧首頁下載完成溯香,想換頁怎么辦?
解決方法:由上圖可知浓恶,其它頁的網(wǎng)址可以直接從首頁推出玫坛。即第n頁的url
="http://tieba.baidu.com/f?kw=%E5%AD%99%E5%85%81%E7%8F%A0&ie=utf-8&pn="+(n-1)*50
問題4:在百度貼吧首頁查找帖子編號 “6383722178”和圖片編號 “4254484e251f95ca67a500d0c6177f3e660952e7”也能找到,為何還要打開具體帖子讀取圖片編號包晰?
解答:百度貼吧首頁獲取的圖片編號只是帖子中圖片編號的一部分而已湿镀,它并不完全。
問題5:在具體帖子的源碼中已經(jīng)可以找到所有圖片編號以及地址伐憾,為何不用這個地址勉痴,而要使用原圖顯示圖片的地址?
解答:直接使用帖子中的圖片地址也是可以下載圖片的塞耕,但它只是按比例縮小的縮略圖蚀腿,不是原圖。
六、參考資料
1莉钙、Python學(xué)習(xí)筆記(二)urllib.urlopen()超時問題 : 504Gateway Time-out
2廓脆、【Python】urllib庫——下載網(wǎng)頁、爬蟲匯總