爬取链接:http://www.doutula.com/photo/list/?page=1
首先F12查看该链接,对比可以看到,没有任何加密,可以解析图片链接,然后下载;
不过要仔细看,有个小坑:图片有两张, 未加载成功显示是白色的图片,加载成功后显示才是正确的;
未加载成功前的网页:
加载成功后:
查看标签页:每个a标签对应一张图片
右键查看源代码,搜索图片名字:
可以发现第一个src链接打开的是一个空白图片,也就是未加载成功的网页图片,显然不是我们想要的,第二个data-original打开显示才是我们想要的,接下来我们可以开始解析,拿到图片链接和图表名字:
xpath解析: 直接把获取到a标签,然后依次遍历:使用yield方法传递:
def parse_page(html):
data = etree.HTML(html)
div_list = data.xpath('//*[@id="pic-detail"]/div/div[2]/div[2]/ul/li/div/div/a')
for i in div_list:
yield{
"pic": i.xpath("./img/@data-original")[0],
"name": i.xpath("./img/@alt")[0]
}
解析完成功,传递给其他函数,执行下载任务:
def save_pic(pic):
title = "表情包合集" # 设置文件名字
url = pic.get("pic") # 拿到url
filename = pic.get("name") # 设置图片名字
imgname = re.sub(r"\\|\*", "", filename) # 过滤特殊字符,防止命名错误
if not os.path.exists(title):
os.mkdir(title)
r = requests.get(url, headers=kv)
try:
if r.status_code == 200:
if url[-3:] == "gif":
file_path = "{0}\{1}.{2}".format(title, imgname, "gif")
if not os.path.exists(file_path):
with open(file_path, "wb") as f:
try:
f.write(r.content)
print("该图片已下载完成")
except:
print("名字格式错误,无法报错")
else:
print("该图片%s已下载" % imgname)
else:
file_path = "{0}\{1}.{2}".format(title, imgname, "jpg")
if not os.path.exists(file_path):
with open(file_path, "wb") as f:
try:
f.write(r.content)
print("该图片已下载完成")
except:
print("名字格式错误,无法报错")
else:
print("该图片%s已下载" % imgname)
except RequestException as e:
print(e, "图片获取失败")
return None
考虑到动态图片的后缀名不一样,因为在拿到url链接,先判断链接的后三个字符串(gif、jpg),两个不同类型的存储,
完成以后,设置翻页,可以无限下载,不用担心发爬措施;
完整代码如下:
import requests
from requests.exceptions import RequestException
from lxml import etree
import os
from multiprocessing import Pool
import time
import re
start_time = time.time()
kv = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36"
}
# 下载图片
def save_pic(pic):
title = "表情包合集" # 设置文件名字
url = pic.get("pic") # 拿到url
filename = pic.get("name") # 设置图片名字
imgname = re.sub(r"\\|\*", "", filename) # 过滤特殊字符,防止命名错误
if not os.path.exists(title):
os.mkdir(title)
r = requests.get(url, headers=kv)
try:
if r.status_code == 200:
if url[-3:] == "gif":
file_path = "{0}\{1}.{2}".format(title, imgname, "gif")
if not os.path.exists(file_path):
with open(file_path, "wb") as f:
try:
f.write(r.content)
print("该图片已下载完成")
except:
print("名字格式错误,无法报错")
else:
print("该图片%s已下载" % imgname)
else:
file_path = "{0}\{1}.{2}".format(title, imgname, "jpg")
if not os.path.exists(file_path):
with open(file_path, "wb") as f:
try:
f.write(r.content)
print("该图片已下载完成")
except:
print("名字格式错误,无法报错")
else:
print("该图片%s已下载" % imgname)
except RequestException as e:
print(e, "图片获取失败")
return None
# 解析请求页面
def parse_page(html):
data = etree.HTML(html)
div_list = data.xpath('//*[@id="pic-detail"]/div/div[2]/div[2]/ul/li/div/div/a')
for i in div_list:
yield{
"pic": i.xpath("./img/@data-original")[0],
"name": i.xpath("./img/@alt")[0]
}
# 获取请求
def get_one_page(i):
url = "http://www.doutula.com/photo/list/?page=" + str(i)
r = requests.get(url, headers=kv)
try:
if r.status_code == 200:
return r.text
except RequestException as e:
print("请求失败:", e)
return None
def main(page):
for i in range(1, page):
html = get_one_page(i)
data = parse_page(html)
for pic in data:
save_pic(pic)
if __name__ == '__main__':
p = Pool(3)
p.map(main, (500, ))
end_time = time.time() - start_time
print("程序运行了%.2f秒" % end_time)
-----------------------------------------------------------------------分割线---------------------------------------------------------------------------------------
这里不建议使用 request.urlretrieve()方法来进行下载,这样很容易遭到反爬,上次使用该方法爬取了250张就爬取不了
我这里用原始的老办法,加了请求头,基本不会有问题,我爬取了500页,毫无问题;基本可以一直爬一直爬;
还有在这里 yield方法非常好用,直接传递过去,当然也可以使用列表的方法,全部存储在列表里,然后依次读取去下载,
不过推荐yield,比较方便。
------------------------------------------------------------------------小诀窍-----------------------------------------------------------------------
最后推荐一个小方法,将代码设置启动功能,直接运行保存到文件中:
新建一个文本文档,将后缀改为bat,然后编辑,输入:python biaoqingbao.py
然后点击run.bat,就开始下载了
就可以看到文件里多了一个文件夹,里面全是表情包: