用selenium自动加载浏览器下载图片

上一篇用requests这个库进行图片的批量下载,只所以可以这样做,是因为豆瓣提供的XHR的接口API,而且接口返回的数据类型为json格式,所以使用起来非常的方便,但是有时候我们需要分析html格式或xml格式的数据,从中提取需要的链接,再进行下载,这时候selenium就派上了用场。

一 人工下载海报

以下载甄子丹的海报为例,我们一般打开豆瓣电影网站:https://movie.douban.com/ 然后输入关键词甄子丹,然后再去下载海报。

二 自动下载处理思路

自动下载,我们需要能够分析出网页种海报图片的具体地址,然后通过程序去下载。

2.1 xpath学习

这里通过xpath去搜寻图片的地址,xpath是 XML Path Language的简称,原来用于搜索xml中的具体路径的,同样适用于搜寻html的元素,简单语法说明下:
xpath基本语法
在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 help获取路径
鼠标在这些海报中来回移动,发现变化的部分,然后修改xpath,去掉前面的固定前缀,把list的下标改成固定值,得到如下:
xpath调整
得到海报的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/来进行查看。

祝大家冬至快乐!

posted @ 2019-12-22 15:00  XGogo  阅读(4261)  评论(0编辑  收藏  举报