1. 預(yù)備工作
在花了兩天半時(shí)間研究學(xué)習(xí)了urllib,requests,bs4,lxml等庫(kù)之后,準(zhǔn)備開始一個(gè)簡(jiǎn)單的實(shí)戰(zhàn)——爬取“下廚房”網(wǎng)站首頁(yè)所有的高清大圖。

首先F12觀察一下這些圖片的真實(shí)地址:

觀察到img =之后有一個(gè)鏈接地址,直接訪問該地址:

顯然這是一個(gè)小圖,不是我要的高清圖。再觀察復(fù)制下來(lái)的鏈接

不難發(fā)現(xiàn),以@為界,鏈接可以分為前后兩個(gè)部分。猜想前一部分是圖片地址,后一部分則是對(duì)圖片進(jìn)行壓縮的參數(shù)。試著刪除@及其之后的部分,再訪問。果然出現(xiàn)了一張高清大圖。

這下子基礎(chǔ)部分基本弄清楚了,預(yù)備動(dòng)作就到這里。
2. 開爬!
終于可以開始寫我的第一只爬蟲了,激動(dòng)~
2.1 獲取頁(yè)面,解析結(jié)構(gòu)
首先,通過requests發(fā)起請(qǐng)求
import requests
from lxml import etree
# 模擬瀏覽器訪問
ua = 'Mozilla/5.0 ' \
'(Windows NT 10.0; Win64; x64) ' \
'AppleWebKit/537.36 (KHTML, like Gecko) ' \
'Chrome/80.0.3987.116 Safari/537.36'
header = {'User-Agent': ua}
r = requests.get("http://www.xiachufang.com/", headers=header)
# r = requests.get("http://httpbin.org/", headers=header)
print(r.text)
et = etree.HTML(r.text)
data = et.xpath('//img/@src')
for i in range(len(data)):
print(data[i])
print(len(data))
控制窗口的輸出信息為:

可見一共輸出了75個(gè)數(shù)據(jù),但是其中包含很大一部分:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAA1BMVEXo6Og4/a9sAAAADUlEQVR42gECAP3/AAAAAgABUyucMAAAAABJRU5ErkJggg
這樣的數(shù)據(jù)。顯然這不是我想要的。打印r.text觀察一下這些數(shù)據(jù)在頁(yè)面中的位置。發(fā)現(xiàn)有
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAA1BMVEXo6Og4/a9sAAAADUlEQVR42gECAP3/AAAAAgABUyucMAAAAABJRU5ErkJggg"
data-src="http://i1.chuimg.com/b7933e0a29d54c53aab854f3ea65c9f3_750w_750h.jpg@2o_50sh_1pr_1l_60w_60h_1c_1e_90q_1wh"
alt="夏夏2013"
width="60"
height="60">
原來(lái)這些用戶分享的圖片,真實(shí)地址在“data-src”屬性中,而非“src”屬性。
查找所有的data-src
data = et.xpath('//img/@data-src')
for i in range(len(data)):
# print(data[i])
pass
print(len(data))
輸出結(jié)果為25,也就是原本鏈接地址為src的被篩選掉了,那么怎么才能保存所有的圖呢?
想到了一個(gè)比較low,但是可行的方案:
- 找到img標(biāo)簽中不包含data-src屬性但包含src屬性中的src值
- 找到img標(biāo)簽中包含data-src屬性的data-src
- 合并前兩步中得到的列表
在代碼中體現(xiàn)為:
et = etree.HTML(r.text)
# 1. 找到img標(biāo)簽中不包含data-src屬性但包含src屬性中的src值
data1 = et.xpath("http://img[not(@data-src) and @src]/@src")
# 2. 找到img標(biāo)簽中包含data-src屬性的data-src
data2 = et.xpath("http://img/@data-src")
# 3. 合并前兩步中得到的列表
img_list= data1 + data2
for i in range(len(img_list)):
print(img_list[i])
# pass
觀察輸出結(jié)果:

結(jié)果列表中存在空項(xiàng)。解決辦法當(dāng)然是去除空項(xiàng):
# 刪除空元素
while '' in img_list:
img_list.remove('')
再觀察輸出結(jié)果:

完美輸出了69個(gè)圖片鏈接。這一部分完成!
2.2 處理img_list列表
由預(yù)備結(jié)果中的分析可知,下一步要做的是對(duì)列表中每一項(xiàng)進(jìn)行分割,只保留高清大圖部分,刪除后面的參數(shù)。也即,保留鏈接中@符號(hào)之前的部分。使用urllib中的parse對(duì)鏈接進(jìn)行分析。
導(dǎo)入urlparse
from urllib.parse import urlparse
for img in img_list:
o = urlparse(img)
關(guān)于urlparse的用法,這里用一個(gè)例子說(shuō)明:
o = urlparse.urlparse("http://www.google.com/search?hl=en&q=urlparse&btnG=Google+Search")
則
| 參數(shù) | 值 |
|---|---|
| o.scheme | 'http' |
| o.netloc | 'www.google.com' |
| o.path | '/search' |
| o.params | '' |
| o.query | 'hl=en&q=urlparse&btnG=Google+Search' |
| o.fragment | '' |
故可以對(duì)列表進(jìn)行下面的處理:
for img in img_list:
o = urlparse(img)
filename = o.path[1:].split('@')[0]
url = "%s://%s/%s" % (o.scheme, o.netloc, filename)
print(url)

完美!
2.3 文件操作
有了真實(shí)的url,下面要做的就是下載圖片并保存到本地了。使用文件操作,首先必須導(dǎo)入python內(nèi)置的os模塊。
import os
初始化文件夾,如果不存在就創(chuàng)建一個(gè):
# 文件操作,初始化xiachufang_image文件夾
image_dir = os.path.join(os.curdir, 'xiachufang_image')
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
2.4 最后一步
遍歷訪問處理后的url,并且以filename保存。(二進(jìn)制寫入)
for img in img_list:
o = urlparse(img)
filename = o.path[1:].split('@')[0]
filepath = os.path.join(image_dir, filename)
url = "%s://%s/%s" % (o.scheme, o.netloc, filename)
print(url)
resp = requests.get(url)
with open(filepath, 'wb') as f:
# 二進(jìn)制以塊寫入
for chunk in resp.iter_content(1024):
f.write(chunk)
基本沒有問題,但是少下載了幾個(gè)圖。再優(yōu)化一下:
for img in img_list:
o = urlparse(img)
filename = o.path[1:].split('@')[0]
filepath = os.path.join(image_dir, filename)
if not os.path.isdir(os.path.dirname(filepath)):
os.mkdir(os.path.dirname(filepath))
url = "%s://%s/%s" % (o.scheme, o.netloc, filename)
print(url)
resp = requests.get(url)
with open(filepath, 'wb') as f:
# 二進(jìn)制以塊寫入
for chunk in resp.iter_content(1024):
f.write(chunk)
看看文件夾,已經(jīng)全部保存,欣賞一下美食吧~






成就感和食欲均滿滿
3. 完整代碼
貼出完整代碼
import os
from urllib.parse import urlparse
import requests
from lxml import etree
# 模擬瀏覽器訪問
ua = 'Mozilla/5.0 ' \
'(Windows NT 10.0; Win64; x64) ' \
'AppleWebKit/537.36 (KHTML, like Gecko) ' \
'Chrome/80.0.3987.116 Safari/537.36'
header = {'User-Agent': ua}
r = requests.get("http://www.xiachufang.com/", headers=header)
# 開始解析
et = etree.HTML(r.text)
# 1. 找到img標(biāo)簽中不包含data-src屬性但包含src屬性中的src值
data1 = et.xpath("http://img[not(@data-src) and @src]/@src")
# 2. 找到img標(biāo)簽中包含data-src屬性的data-src
data2 = et.xpath("http://img/@data-src")
# 3. 合并前兩步中得到的列表
img_list = data1 + data2
# 刪除空元素
while '' in img_list:
img_list.remove('')
# 文件操作,初始化xiachufang_image文件夾
image_dir = os.path.join(os.curdir, 'xiachufang_image')
# if not os.path.isdir(image_dir):
# os.mkdir(image_dir)
for img in img_list:
o = urlparse(img)
filename = o.path[1:].split('@')[0]
filepath = os.path.join(image_dir, filename)
if not os.path.isdir(os.path.dirname(filepath)):
os.mkdir(os.path.dirname(filepath))
url = "%s://%s/%s" % (o.scheme, o.netloc, filename)
print(url)
resp = requests.get(url)
with open(filepath, 'wb') as f:
# 二進(jìn)制以塊寫入
for chunk in resp.iter_content(1024):
f.write(chunk)