上一篇用requests這個庫進行圖片的批量下載,只所以可以這樣做,是因為豆瓣提供的XHR的接口API,而且接口返回的數據類型為json格式,所以使用起來非常的方便,但是有時候我們需要分析html格式或xml格式的數據,從中提取需要的鏈接,再進行下載,這時候selenium就派上了用場。
一 人工下載海報
以下載甄子丹的海報為例,我們一般打開豆瓣電影網站:https://movie.douban.com/ 然后輸入關鍵詞甄子丹,然后再去下載海報。
二 自動下載處理思路
自動下載,我們需要能夠分析出網頁種海報圖片的具體地址,然后通過程序去下載。
2.1 xpath學習
這里通過xpath去搜尋圖片的地址,xpath是 XML Path Language的簡稱,原來用於搜索xml中的具體路徑的,同樣適用於搜尋html的元素,簡單語法說明下:
在python中,適用lxml庫可以將html轉成xpath對象,然后進行分析,非常方便,lxml庫可以對html未閉合的標簽元素做容錯處理。
看一個簡單的例子:
from lxml import etree
text = '''
<div>
<ul>
<li class="item-0"><a href="link1.html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a href="link5.html">fifth item</a>
</ul>
</div>
'''
解析:
#讀取字符串,讀取文件可以用
#html=etree.parse('test.html',etree.HTMLParser())
html = etree.HTML(text)
#轉成補全字節
r = etree.tostring(html,encoding='utf-8')
#打印補全結果
#print(r.decode('utf-8'))
#搜下下面所有為li的子孫節點
resultLi = html.xpath("//li")
print("//li: "+ str(resultLi))
#搜尋li節點下面的a節點,並取href屬性的值
reLiA = html.xpath("//li/a/@href")
print("//li/a/@href :"+ str(reLiA))
#獲取href的屬性值為link2.html的a節點的上層節點的class熟悉值
reClass=html.xpath('//a[@href="link2.html"]/../@class')
print('//a[@href="link2.html"]/../@class :'+ str(reClass))
#搜尋li節點下面的a節點,並取href屬性的值
reLiText = html.xpath("//li/a/text()")
print("//li/a/text() :"+ str(reLiText))
上述代碼本來是一段,在markdown中解析有問題,改成兩段了。
打印結果如下:
//li: [<Element li at 0x1cb14b89908>, <Element li at 0x1cb14b89988>, <Element li at 0x1cb14b899c8>, <Element li at 0x1cb14b89a08>, <Element li at 0x1cb14b89a48>]
//li/a/@href :['link1.html', 'link2.html', 'link3.html', 'link4.html', 'link5.html']
//a[@href="link2.html"]/../@class :['item-1']
//li/a/text() :['first item', 'second item', 'third item', 'fourth item', 'fifth item']
2.2 圖片的xpath路徑提取
通過上面的例子,xpath的語法雖然不復雜,但是有時候還要記憶,幸好chorme瀏覽器有個xpath helper插件,安裝上之后鼠標放在圖片上,按下ctrl+shift+x鍵,彈出對話框:
鼠標在這些海報中來回移動,發現變化的部分,然后修改xpath,去掉前面的固定前綴,把list的下標改成固定值,得到如下:
得到海報的xpath:
//div[@id='recent_movies']/div[@class='bd']/ul[@class='list-s']/*/div[@class='pic']/a/img/@src
這個xpath可以獲取到的圖片地址為:
https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2577437186.webp
https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2537133715.webp
https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2542380253.webp
https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2528842218.webp
https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2499052494.webp
我們用selenium模擬瀏覽器來進行html的加載和xpath的查詢,獲取到地址后,就可以通過下載函數進行圖片下載。
三. 利用selenium 進行海報的下載
在豆瓣電影中搜索”甄子丹”
https://search.douban.com/movie/subject_search?search_text=%E7%94%84%E5%AD%90%E4%B8%B9&cat=1002
調整下xpath:
//div[1]/div[@class='sc-bZQynM jbSySb sc-bxivhb gemzcp'][*]/div[@class='item-root']/a[@class='cover-link']/img[@class='cover']/@src
得到的15個結果:
https://img9.doubanio.com/view/photo/s_ratio_poster/public/p2577437186.webp
...
如果需要翻頁的話,鏈接加個start=15說明從16個海報開始展示。
獲取電影名稱:
//div[@class='_ytukbl17q']/div[1]/div[@class='sc-bZQynM cBnAay sc-bxivhb gemzcp'][*]/div[@class='item-root']/div[@class='detail']/div[@class='title']/a[@class='title-text']
得到結果:
武俠 (2011)
西游記之大鬧天宮 (2014)
...
最終下載代碼:
# -*- coding: utf-8 -*-
import requests
import json
import sys
import io
import os
from selenium import webdriver
from lxml import etree
def download(picPath,src, id):
if not os.path.isdir(picPath):
os.mkdir(picPath)
dir = picPath+'/' + str(id) + '.webp'
print(src)
imageHeader = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
#'accept-encoding': 'gzip, deflate',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',
'sec-fetch-mode': 'navigate',
'sec-fetch-site': 'none',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
try:
pic = requests.get(src,headers=imageHeader,timeout=50)
fp = open(dir, 'wb')
fp.write(pic.content)
fp.close()
except requests.exceptions.ConnectionError:
print('Sorrry,image cannot downloaded, url is error{}.'.format(src))
def query_img(query,downloadUrl):
realUrl = downloadUrl.format(query)
print(realUrl)
driver = webdriver.Chrome('D:\\py3\\Lib\\site-packages\\selenium\\webdriver\\chrome\\chromedriver_win32\\chromedriver.exe')
driver.get(realUrl)
#解析html
html = etree.HTML(driver.page_source)
image_url_path = "//div[1]/div[*]/div[@class='item-root']/a[@class='cover-link']/img[@class='cover']/@src"
movie_name_path = "//div/div[1]/div[*]/div[@class='item-root']/div[@class='detail']/div[@class='title']/a[@class='title-text']/text()"
urls = html.xpath(image_url_path)
names = html.xpath(movie_name_path)
picPath = 'F:\\python\\images'
for (url,name) in zip(urls,names):
download(picPath,url,name)
if __name__ == "__main__":
query = '甄子丹'
url = 'https://search.douban.com/movie/subject_search?search_text=\'{}\'&cat=1002'
query_img(query,url)
注意:這里面利用chrome瀏覽器的driver,不同的瀏覽器的driver可以到https://selenium-python.readthedocs.io/installation.html鏈接去下載,主要要和自己的瀏覽器版本保持一致。
chrome瀏覽器的版本可以通過在瀏覽器中輸入:chrome://version/來進行查看。
祝大家冬至快樂!