今天我们来爬取一个图片网站花瓣网,写一个比较简单的图片下载的爬虫;
图片太多了,只截了这些图片,大概几千张;
对,没错,就是你们喜欢的胖迪,
1、首先分析一下花瓣网图片的加载方式
打开花瓣网首页,搜索“迪丽热巴”,
下拉加载出第二页的图片时弹出登录框,只有登录账号才可以继续加载后面的所有图片;
可以看出,花瓣网的图片加载是异步加载的方式,这时我们可以选择selenium模拟登录网页模仿浏览器的操作不断的下拉加载出所有的图片;
2、主要思想:
首先要登录账号,输入要搜索的图片,每次下拉加载出当前页面的图片后,提取对于图片的url存到一个列表里,由于每页图片是20张,所以我这里在下载图片的时候也是每次存20个url就去下载对应的这20张图片;
3、准备工作:
安装selenium的库,pip或者下载到本地安装都OK;
下面是安装Phantomjs或者Chrome
具体下载可自行百度,或者参考下面的博客,这里感谢这位博主
在Windows下安装PIP+Phantomjs+Selenium
4、下面直接上代码
from selenium import webdriver
import time
import os
import requests
class Huaban():
#获取图片url并存到列表urls_list
def get_picture_url(self, content):
global path
path = "E:\spider\pictures\huaban" + '\\' + content
# 保存图片到磁盘文件夹 file_path中,默认为当前脚本运行目录下的文件夹
if not os.path.exists(path):
os.makedirs(path)
url = "http://huaban.com"
# 使用Chrome浏览器模拟打开网页,但是要把下载的chromedriver.exe放在python的文件路径下,
# 调试好之后换成PhantomJs,速度应该会快一点
# driver = webdriver.PhantomJs()
# 下拉滑动浏览器屏幕,具体下拉多少根据自己实际情况决定
driver = webdriver.PhantomJS()
#driver = webdriver.Chrome()
# 设置全屏
driver.maximize_window()
driver.get(url)
time.sleep(8)
# 点击登录、呼起登录窗口
driver.find_elements_by_xpath('//a[@class="login btn wbtn"]')[0].click()
# sign in the username
try:
driver.find_elements_by_xpath('//input[@name="email"]')[0].send_keys('花瓣账号')
print('user success!')
except:
print('user error!')
time.sleep(3)
# sign in the pasword
try:
driver.find_elements_by_xpath('//input[@name="password"]')[0].send_keys('账号密码')
print('pw success!')
except:
print('pw error!')
time.sleep(3)
# click to login
try:
driver.find_elements_by_xpath('//a[@class="btn btn18 rbtn"]')[0].click()
print('click success!')
except:
print('click error!')
time.sleep(3)
#搜索图片
driver.find_elements_by_xpath('//input[@placeholder="搜索你喜欢的"]')[0].send_keys(content)
driver.find_elements_by_xpath('//form[@id="search_form"]/a')[0].click()
time.sleep(5)
i = 0
page = 1
global name
global store_path
global urls_list
urls_list = []
#获取图片的总数
pictures_count = driver.find_elements_by_xpath('//a[@class="selected"]/i')[0].text
print(pictures_count)
pages = int(int(pictures_count) / 20)
print(pages)
#匹配到图片url所在的元素
url_elements = driver.find_elements_by_xpath('//span[@class="stop"]/../img')
#遍历图片元素的列表获取图片的url
for url_element in url_elements:
picture_url = url_element.get_attribute("src")[:-3] + "658"
#防止获取重复的图片url
if picture_url not in urls_list:
urls_list.append(picture_url)
while page <= pages:
while len(urls_list) < 20*page:
driver.execute_script("window.scrollBy(0,1000)")
time.sleep(3)
url_elements = driver.find_elements_by_xpath('//span[@class="stop"]/../img')
for url_element in url_elements:
picture_url = url_element.get_attribute("src")[:-3] + "658"
if picture_url not in urls_list:
urls_list.append(picture_url)
print("第%s页" % page)
for download_url in urls_list[20*(page-1):20*page]:
i += 1
name = content + "_" + str(i)
store_path = name + '.jpg'
self.store(download_url)
page += 1
#最后一页
print("第%s页" % int(page))
while len(urls_list) < int(pictures_count):
driver.execute_script("window.scrollBy(0,1000)")
time.sleep(3)
url_elements = driver.find_elements_by_xpath('//span[@class="stop"]/../img')
for url_element in url_elements:
picture_url = url_element.get_attribute("src")[:-3] + "658"
if picture_url not in urls_list:
urls_list.append(picture_url)
for download_url in urls_list[20*(page-1): ]:
i += 1
name = content + "_" + str(i)
store_path = name + '.jpg'
self.store(download_url)
#存储图片到本地
def store(self, picture_url):
picture = requests.get(picture_url)
f = open(path + '\\'+ store_path, 'wb')
f.write(picture.content)
print('正在保存图片:' + picture_url)
print('文件:' + name)
if __name__ == "__main__":
content = '迪丽热巴'
huaban = Huaban()
huaban.get_picture_url(content)
下面打印的结果可以看出一共有7265张图片
小结:
1、对于刚开始用selenium的同学可以先选择chromedriver,虽然这个有界面浏览器可能爬起来比较慢,但是可以通过报错或者看下浏览器暂停的界面判断出是哪里的问题(比如时长暂停的时间太短了,没有加载出元素,又或者在加载中...)
2、其实这么简单的一个爬虫,里面的坑还不少的,
比如,本地的思路是每次获取记载的url,再遍历下载url列表里的图片,但是如果你是直接获取图片url所在的元素并存到列表里,后面再取出相应的url下载图片,虽然看起来回避之前的过程要简单一点,但是再运行到一半(大概几百张后,这个具体看运气咯)就会报错:
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
大概意思是说:意思就是Element已经过时,没有和当前页面进行绑定,主要是页面刷新或者跳转引起的,需要重新获取一次元素。
修改的方法:
获取元素之后,使用元素之前要重新花去一次元素
所以这里选择了获取元素后直接取url存到列表就比较稳定了;
3、这里还有一个调试比较麻烦的就是,每次下拉滑动的距离以及每次停留的时间大小,太大或大小都有可能导致提前结束爬虫;
4、这里其实还有一个思路就是:最开始的分析可以看出,每次加载出一页(20张)图片,就会有一个对应的url,我们可以通过构造这个每页的url获取所有的图片,这里只是提供一个思路,有兴趣的同学可以简单尝试一下是否可行;
5、最开始爬的时候可以先选择一些图片总数比较少的搜索词,这样可以比较快的看到效果,尽快调通,然后再试一些比较多的图片;
6、这里爬数量比较多的图片,可能速度稍微有点慢,用scrapy或者多线程的可能会比较快一点;
以上是小弟个人见解,如有错误请麻烦指出,多谢!