首先讲下爬取网站图片是动态加载的(参考文章:动态爬取百度图),以百度图片为例,打开百度图片,我搜索的关键字是“猫”:
http://image.baidu.com/search/index?tn=baiduimage&ps=1&ct=201326592&lm=-1&cl=2&nc=1&ie=utf-8&word=猫
在看到搜索出的图片的网页按F12,出现下图;
切换右侧标签到Network,然后网页往下拉,这时浏览器地址栏网址未变,而网页中图片却一张张增加(这就是所说的动态加载),说明网页在后台与服务器交互数据。
有列写着XHR,这个的英文全名为XmlHttpRequest,即可扩展超文本传输请求。Xml可扩展标记语言,Http超文本传输协议,Request请求。XMLHttpRequest对象可以在不向服务器提交整个页面的情况下,实现局部更新网页。当页面全部加载完毕后,客户端通过该对象向服务器请求数据,服务器端接受数据并处理后,向客户端反馈数据。 点开Network标签中 XHR列中的某一条,在右侧Hearders的Request URL发现末尾的“pn=…………=”这些内容,对比其他XHR链接的Request URL,可以发现,基本上是一样的,除了末尾“pn=…………=”一点点差异。
只是pn的值不一样,测试发现,pn应该是表示当前请求的图片序号,rn表示更新显示图片的数量。 pn=90&rn=30&gsm=5a&1484307466221=
pn=120&rn=30&gsm=5a&1484307466223=
pn=150&rn=30&gsm=78&1484307469213=
pn=180&rn=30&gsm=78&1484307469214=
pn=210&rn=30&gsm=b4&1484307553244=
推荐一款Chrom的插件,Json handle。很方便。 百度云下载地址。链接:http://pan.baidu.com/s/1qXZEjaW 密码:nxr5
现在知道了,其实我们只要不断访问这个Request URL,改变他的pn值理论上就可以实现下载多张图片了。
如果想看关键字的编码可用以下语句:
>>>import urllib
>>>keyword="猫"
>>>keyword=urllib.quote(keyword)
>>>keyword
获取当前页所有图片的链接
右键点击查看网页html源文件,发现同一张图片共有4种链接(如下图):
主要区别是分辨率不同,objURL是图片的源也是最清楚的一张。经测试,其他三个都要反爬虫措施,用浏览器可以打开,但是刷新一次就403 Forbidden。用爬虫获取不到图片。
第四种objURL是指图片的源网址,获取该网址会出现三种情况:
1.正常。可继续下载;
2.403 Forbidden。用continue跳过;
3.出现异常。用try excep处理;
图片的网址都是这样的格式: "objURL":"网址", 那就好办了, 直接用正则表达式就能解决
import re
pattern_pic = '"objURL":"(.*?)",'
# 这里的html就是网页的源代码的内容, 此处不介绍, 稍后给出
pic_list = re.findall(pattern_pic, html, re.S) # 存储当前页的所有关键字的图片的url的列表
其中正则表达式的解释和例子推荐看这篇文章:import re
获取当前页的下一页的链接
用正则得出:
pattern_fanye = '<a href="(.*)" class="n">下一页</a>'
fanye_url = re.findall(pattern_fanye, html)[0] # 下一页的链接
获取所有页的图片链接
图片的网址都是这样的格式: "objURL":"网址", 直接用正则表达式就能解决:
import re
pattern_pic = '"objURL":"(.*?)",'
# 这里的html就是网页的源代码的内容,
pic_list = re.findall(pattern_pic, html, re.S) # 存储当前页的所有关键词的图片的url的列表
获取所有页的图片的链接
上面已经根据当前页的url得到了当前页的所有图片的链接, 以及下一页的url. 如此, 循环下去, 即可得到每一页的所有图片的链接.
all_pic_list = [] # 存储所有翻页的所有图片的链接的列表
while 1:
all_pic_list.extend(pic_list)
if 循环完所有翻页:
break
下载图片
知道图片链接了,直接下载:
for i, pic_url in enumerate(all_pic_list):
pic = requests.get(pic_url)
string = str(i + 1) + '.jpg'
with open(string, 'wb') as f:
f.write(pic.content)
完整源代码如下:(也可参考这篇爬泰勒斯威夫的图片,源码和以下类似:爬取百度图片(泰勒))
# coding=utf-8
"""根据搜索词下载百度图片"""
import re
import sys
import urllib
import requests
def get_onepage_urls(onepageurl):
"""获取单个翻页的所有图片的urls+当前翻页的下一翻页的url"""
if not onepageurl:
print('已到最后一页, 结束')
return [], ''
try:
html = requests.get(onepageurl).text
except Exception as e:
print(e)
pic_urls = []
fanye_url = ''
return pic_urls, fanye_url
pic_urls = re.findall('"objURL":"(.*?)",', html, re.S)
fanye_urls = re.findall(re.compile(r'<a href="(.*)" class="n">下一页</a>'), html, flags=0)
fanye_url = 'http://image.baidu.com' + fanye_urls[0] if fanye_urls else ''
return pic_urls, fanye_url
def down_pic(pic_urls):
"""给出图片链接列表, 下载所有图片"""
for i, pic_url in enumerate(pic_urls):
try:
pic = requests.get(pic_url, timeout=15)
string = str(i + 1) + '.jpg'
with open(string, 'wb') as f:
f.write(pic.content)
print('成功下载第%s张图片: %s' % (str(i + 1), str(pic_url)))
except Exception as e:
print('下载第%s张图片时失败: %s' % (str(i + 1), str(pic_url)))
print(e)
continue
if __name__ == '__main__':
keyword = '猫' # 关键词, 改为你想输入的词即可, 相当于在百度图片里搜索一样
url_init_first = r'http://image.baidu.com/search/flip?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1497491098685_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&ctd=1497491098685%5E00_1519X735&word='
url_init = url_init_first + urllib.quote(keyword, safe='/')
all_pic_urls = []
onepage_urls, fanye_url = get_onepage_urls(url_init)
all_pic_urls.extend(onepage_urls)
fanye_count = 0 # 累计翻页数
while 1:
onepage_urls, fanye_url = get_onepage_urls(fanye_url)
fanye_count += 1
print('第%s页' % fanye_count)
if fanye_url == '' and onepage_urls == []:
break
all_pic_urls.extend(onepage_urls)
down_pic(list(set(all_pic_urls)))
用正则方式爬取其他非百度图片网站的图,可参考:爬取游戏网页图片
代码:
其实很简单,我们直接看下整体的代码:
#coding = utf-8
import urllib
import re
def getHtml(url):
page = urllib.urlopen(url)
html = page.read()
return html
def getImg(html):
reg = 'src="(.+?\.jpg)" alt='
imgre = re.compile(reg)
imglist = re.findall(imgre, html)
x = 0
for imgurl in imglist:
urllib.urlretrieve(imgurl, '%s.jpg' % x)
x+=1
return imglist
html = getHtml("http://pic.yxdown.com/list/0_0_1.html")
print getImg(html)
导入库:
第一行的utf-8是为了支持中文。 这里我们导入了两个库,分别是 urllib 和 re。urllib 是用来进行 url 网络请求的,而 re 是一个正则表达式匹配的库。这里我们要先对网站进行模拟请求,然后找到网站中的图片进行下载。
请求网站:
第一个方法:getHtml。 这就是用来模拟浏览器访问网站的,参数 url 是要访问的网站链接,这里我们在下面的变量 html 处调用了这个方法,其访问的 url 是一个图片网站,关于选择访问网站还有一点等下要说一下。 在这个方法中,我们先用了 urllib 库的 urlopen 方法来打开网站,然后通过 read 方法来获取网站的源代码,其实就跟在网页中“右键–>检查“是一个意思。最后返回了读取到的网站源代码。 上面说了要注意的一点是,由于很多网站会禁止人们随意爬取数据,有反爬虫的技术,所以在选择要爬取的网站的时候,最好先通过这个方法获取网站源代码,然后 print 输出 html 变量看一下获取到的内容是否是正常的网页源代码,而不是403之类的禁止访问,如果被禁止了,那么自然也不可能爬取到数据了。
找到图片:
接下来是一个 getImg 方法。 在这个方法中,我们设置了一个正则表达式,用来在网页源代码中找到图片的资源路径,这个正则表达式要根据不同的网站去具体设置,比如我爬取的这个网站,图片对应的源代码是这样的:
因此我们设置的正则表达式就是 reg = ‘src=”(.+?.jpg)” alt=’ ,其实就是根据图片资源路径前后的内容来限制的。 这里也要注意一点,有的网站做了动静分离,图片有其单独的完整资源路径,而有的是直接是相对位置,这时候要么对其路径进行处理,但大多时候你并不知道怎么处理才能拼出完整路径,因此还是找有完整资源路径的图片来试验比较好。 紧接着用 re 库的 compile 函数将正则表达式转换成正则表达式对象,然后使用 findall 函数寻找 html 网页源代码中包含的匹配 imgre 的所有内容,返回一个序列。我们可以输出这个序列,可以看到大量图片资源路径组成的一个序列,如果没爬取到,就是个空序列了。 下载图片 最后一步就是下载图片,这里我们用 for 循环,将图片资源路径中的每个图片,使用 urllib 库的 urlretrieve 函数来下载图片,这个函数其实可以接受很多参数,这里我们设置了要下载的图片资源路径和要命名的名字(我们使用一个变量x来对每个图片依次命名为0,1,2…),还可以设置下载路径、用来显示下载进度的回调函数等等。如果不设置下载路径默认会下载到代码文件当前所在的文件夹。
执行
现在,去执行一次代码就可以,直接将代码放入一个 .py 文件中,使用终端进入其文件位置,敲入 python xxx.py 命令就可以。
用多线程对图片进行爬取:多线程爬取百度图,多线程动态爬取百度图
通过关键字爬取多张百度图片
这个爬取妹子的链接……作者还真是人才,写的蛮好的,故推荐:爬取妹子图片
这个爬取百度图片,鉴定可行:爬取百度图片
# -*- coding: utf-8 -*-
import re
import requests
from urllib import error
from bs4 import BeautifulSoup
import os
num = 0
numPicture = 0
file = ''
List = []
def Find(url, A):
global List
print('正在检测图片总数,请稍等.....')
t = 0
i = 1
s = 0
while t < 1000:
Url = url + str(t)
try:
# 这里搞了下
Result = A.get(Url, timeout=7, allow_redirects=False)
except BaseException:
t = t + 60
continue
else:
result = Result.text
pic_url = re.findall('"objURL":"(.*?)",', result, re.S) # 先利用正则表达式找到图片url
s += len(pic_url)
if len(pic_url) == 0:
break
else:
List.append(pic_url)
t = t + 60
return s
def recommend(url):
Re = []
try:
html = requests.get(url, allow_redirects=False)
except error.HTTPError as e:
return
else:
html.encoding = 'utf-8'
bsObj = BeautifulSoup(html.text, 'html.parser')
div = bsObj.find('div', id='topRS')
if div is not None:
listA = div.findAll('a')
for i in listA:
if i is not None:
Re.append(i.get_text())
return Re
def dowmloadPicture(html, keyword):
global num
# t =0
pic_url = re.findall('"objURL":"(.*?)",', html, re.S) # 先利用正则表达式找到图片url
print('找到关键词:' + keyword + '的图片,即将开始下载图片...')
for each in pic_url:
print('正在下载第' + str(num + 1) + '张图片,图片地址:' + str(each))
try:
if each is not None:
pic = requests.get(each, timeout=7)
else:
continue
except BaseException:
print('错误,当前图片无法下载')
continue
else:
string = file + r'\\' + keyword + '_' + str(num) + '.jpg'
fp = open(string, 'wb')
fp.write(pic.content)
fp.close()
num += 1
if num >= numPicture:
return
if __name__ == '__main__': # 主函数入口
##############################
# 这里加了点
headers = {
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Connection': 'keep-alive',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
'Upgrade-Insecure-Requests': '1'
}
A = requests.Session()
A.headers = headers
###############################
word = input("请输入搜索关键词(可以是人名,地名等): ")
# add = 'http://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=%E5%BC%A0%E5%A4%A9%E7%88%B1&pn=120'
url = 'https://image.baidu.com/search/flip?tn=baiduimage&ie=utf-8&word=' + word + '&pn='
# 这里搞了下
tot = Find(url, A)
Recommend = recommend(url) # 记录相关推荐
print('经过检测%s类图片共有%d张' % (word, tot))
numPicture = int(input('请输入想要下载的图片数量 '))
file = input('请建立一个存储图片的文件夹,输入文件夹名称即可')
y = os.path.exists(file)
if y == 1:
print('该文件已存在,请重新输入')
file = input('请建立一个存储图片的文件夹,)输入文件夹名称即可')
os.mkdir(file)
else:
os.mkdir(file)
t = 0
tmp = url
while t < numPicture:
try:
url = tmp + str(t)
# 这里搞了下
result = A.get(url, timeout=10, allow_redirects=False)
except error.HTTPError as e:
print('网络错误,请调整网络后重试')
t = t + 60
else:
dowmloadPicture(result.text, word)
t = t + 60
print('当前搜索结束,感谢使用')
print('猜你喜欢')
for re in Recommend:
print(re, end=' ')
需要你安装bs4 ,用pip install bs4就行,缺啥就pip install啥~