1. 預(yù)備工作
在花了兩天半時間研究學習了urllib池充,requests躯保,bs4,lxml等庫之后贩猎,準備開始一個簡單的實戰(zhàn)——爬取“下廚房”網(wǎng)站首頁所有的高清大圖熊户。
首先F12觀察一下這些圖片的真實地址:
觀察到img =之后有一個鏈接地址,直接訪問該地址:
顯然這是一個小圖吭服,不是我要的高清圖嚷堡。再觀察復(fù)制下來的鏈接
不難發(fā)現(xiàn),以@為界艇棕,鏈接可以分為前后兩個部分蝌戒。猜想前一部分是圖片地址,后一部分則是對圖片進行壓縮的參數(shù)欠肾。試著刪除@及其之后的部分瓶颠,再訪問。果然出現(xiàn)了一張高清大圖刺桃。
這下子基礎(chǔ)部分基本弄清楚了粹淋,預(yù)備動作就到這里。
2. 開爬瑟慈!
終于可以開始寫我的第一只爬蟲了桃移,激動~
2.1 獲取頁面,解析結(jié)構(gòu)
首先葛碧,通過requests發(fā)起請求
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個數(shù)據(jù)借杰,但是其中包含很大一部分:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAAA1BMVEXo6Og4/a9sAAAADUlEQVR42gECAP3/AAAAAgABUyucMAAAAABJRU5ErkJggg
這樣的數(shù)據(jù)。顯然這不是我想要的。打印r.text觀察一下這些數(shù)據(jù)在頁面中的位置。發(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">
原來這些用戶分享的圖片膘魄,真實地址在“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的被篩選掉了,那么怎么才能保存所有的圖呢?
想到了一個比較low济蝉,但是可行的方案:
- 找到img標簽中不包含data-src屬性但包含src屬性中的src值
- 找到img標簽中包含data-src屬性的data-src
- 合并前兩步中得到的列表
在代碼中體現(xiàn)為:
et = etree.HTML(r.text)
# 1. 找到img標簽中不包含data-src屬性但包含src屬性中的src值
data1 = et.xpath("http://img[not(@data-src) and @src]/@src")
# 2. 找到img標簽中包含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é)果列表中存在空項。解決辦法當然是去除空項:
# 刪除空元素
while '' in img_list:
img_list.remove('')
再觀察輸出結(jié)果:
完美輸出了69個圖片鏈接菠发。這一部分完成王滤!
2.2 處理img_list列表
由預(yù)備結(jié)果中的分析可知,下一步要做的是對列表中每一項進行分割滓鸠,只保留高清大圖部分雁乡,刪除后面的參數(shù)。也即糜俗,保留鏈接中@符號之前的部分蔗怠。使用urllib中的parse對鏈接進行分析墩弯。
導(dǎo)入urlparse
from urllib.parse import urlparse
for img in img_list:
o = urlparse(img)
關(guān)于urlparse的用法,這里用一個例子說明:
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 | '' |
故可以對列表進行下面的處理:
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 文件操作
有了真實的url,下面要做的就是下載圖片并保存到本地了锌钮。使用文件操作桥温,首先必須導(dǎo)入python內(nèi)置的os模塊。
import os
初始化文件夾梁丘,如果不存在就創(chuàng)建一個:
# 文件操作,初始化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保存。(二進制寫入)
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:
# 二進制以塊寫入
for chunk in resp.iter_content(1024):
f.write(chunk)
基本沒有問題氛谜,但是少下載了幾個圖掏觉。再優(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:
# 二進制以塊寫入
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標簽中不包含data-src屬性但包含src屬性中的src值
data1 = et.xpath("http://img[not(@data-src) and @src]/@src")
# 2. 找到img標簽中包含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:
# 二進制以塊寫入
for chunk in resp.iter_content(1024):
f.write(chunk)