Python爬取百度图片
1.首先要知道从哪儿去查找,如果根据在爬取豆瓣书单、电影等网页的经验是行不通的。因为百度图片所在网页是用ajax技术加载,属于动态网站。
不信。。。>>>请君看吼--------
网页上F12小箭头点击迪丽热巴第一张图片,我们确实可以看到图片地址。

但当我们右击鼠标编辑HTML来赋值图片地址时,发现……

因此,爬取百度图片并不能使用我们爬取豆瓣那一套路来实现,得想新的法子。
于是,我们点击network(网络),鼠标拖至图片处向下滑动,会出现如图以acjson开头的xhr类型文件。

而我们需要的图片地址就“藏”在这些文件内。
点击一个打开我们会继续看到>>>

在这些内容中我们细心一点便可以发现有多个如图中蓝色高亮的以.jpg结尾的字符,我们不妨赋值在网页中打开一看,便知——这就是我们要下载到本地的图片。
接下来,既然以acjson开头的xhr类型文件会随着鼠标的拖到而增加,我们不妨对比一下他们URL的区别。
我随便复制两个进行对比:
https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=迪丽热巴&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word=迪丽热巴&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=210&rn=30&gsm=d2&1597644983516=
: https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord=迪丽热巴&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word=迪丽热巴&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn=240&rn=30&gsm=f0&1597644983658=
虽然比较辣眼睛,但我们可以很明显的看到两个网址其实只要pn参数和gsm参数属性值不同,因此我们在代码中便可以使用循环来请求响应这些网址。当然,这里需要知道的是我们发现pn参数有规律可循但gsm没有,既然没有也不必惊慌,我们不要就是。如果不相信,可以去掉后面的&gsm=f0&1597644983658再把地址放到网页中查看,发现是一模一样。
到勒这一步,我们要做的工作便是编写代码来提取并保存图片。
import requests
import re
from urllib.parse import quote
1.导入三方库,requests用来请求网址响应并以文本形式获得网页源代码,re用来提取图片地址,quote用来将不符合URL标准的字符转化为符合标准。
1.获得网页的源代码,并以文本形式返回
def get_text(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"
}
req = requests.get(url=url,headers=headers)
return req.text
2.获得网页的源代码,并以文本形式返回(text为文本形式,content为字节形式)
2.对源代码进行提取图片地址,在每一个网址的源代码中都有30张图片,因此正则表达式提取的元素个数有30个
def get_jpg(source):
data_list = re.findall(r'"thumbURL":"(.*?)",',source)
return data_list
3.在源代码中找到图片地址并以列表形式返回
3.请求并响应每一张图的代码,返回字节形式并保存在本地
def get_bytes(url_one):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"
}
rep = requests.get(url=url_one,headers=headers)
return rep.content
4.获取图片地址后请求网址获得源代码的字节形式,这便是图片链接。
4.保存每一张图的代码的字节形式
def save_pic(content,numb):
with open("liqin/{}.jpg".format(numb), 'ab+') as fp:
fp.write(content)
5.将文件保存到本地
def main():
print(time.time())
name = input("请输入搜索图片的关键词: ")
key_word = quote(name)
page_num = input("请输入下载图片的数量: ")
req = re.findall(r'(\d+)',page_num)
while len(req) == 0:
page_num = input("输入格式不对!请重新输入下载图片的数量: ")
req = re.findall(r'(\d+)', page_num)
num = int(req[0])
if num % 30 == 0:
page = num//30
else:
page = num//30+1
print(num)
for ele in range(30,page*30+30,30):
url = "https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn={}&rn=30=".format(
key_word, key_word, ele)
html = get_text(url) #返回每一个网址的源代码
jpg_list = get_jpg(html) #返回每一个网址内的图片地址
i = 1 #每一张图的序号
for jpg in jpg_list:
if int(ele)-30+i == num+1:
break
print('第%d张图片正在下载'%(int(ele)-30+i))
content = get_bytes(jpg) #将每一张图片源代码的字节形式返回
save_pic(content,ele-30+i) #将每一张图保存到本地
print('第%d图片下载完成' % (int(ele)-30+i))
i += 1 #随着每一张图的保存,序号相应加一,30张图保存后,i再次赋值为1代表每一个网址的第一张图
我的main函数代码比较多,其原因在于对输入图片数量的格式比较严格防止输入其他字符导致程序结束,当然这个程序没有用到异常处理机制,接下来我会继续改进。最后是函数入口
if name == "main":
main()
完整代码:
import requests
import re
from urllib.parse import quote
import time
def get_text(url):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"
}
req = requests.get(url=url,headers=headers)
return req.text
def get_jpg(source):
data_list = re.findall(r'"thumbURL":"(.?)",',source)
return data_list
def get_bytes(url_one):
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0"
}
rep = requests.get(url=url_one,headers=headers)
return rep.content
def save_pic(content,numb):
with open("liqin/{}.jpg".format(numb), 'ab+') as fp:
fp.write(content)
def main():
print(time.time())
name = input("请输入搜索图片的关键词: ")
key_word = quote(name)
page_num = input("请输入下载图片的数量: ")
req = re.findall(r'(\d+)',page_num)
while len(req) == 0:
page_num = input("输入格式不对!请重新输入下载图片的数量: ")
req = re.findall(r'(\d+)', page_num)
num = int(req[0])
if num % 30 == 0:
page = num//30
else:
page = num//30+1
print(num)
for ele in range(30,page30+30,30):
url = "https://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&is=&fp=result&queryWord={}&cl=2&lm=-1&ie=utf-8&oe=utf-8&adpicid=&st=-1&z=&ic=0&hd=&latest=©right=&word={}&s=&se=&tab=&width=&height=&face=0&istype=2&qc=&nc=1&fr=&expermode=&force=&pn={}&rn=30=".format(
key_word, key_word, ele)
html = get_text(url) #返回每一个网址的源代码
jpg_list = get_jpg(html) #返回每一个网址内的图片地址
i = 1 #每一张图的序号
for jpg in jpg_list:
if int(ele)-30+i == num+1:
break
print('第%d张图片正在下载'%(int(ele)-30+i))
content = get_bytes(jpg) #将每一张图片源代码的字节形式返回
save_pic(content,ele-30+i) #将每一张图保存到本地
print('第%d图片下载完成' % (int(ele)-30+i))
i += 1 #随着每一张图的保存,序号相应加一,30张图保存后,i再次赋值为1代表每一个网址的第一张图
print(time.time())
if name == "main":
main()
由于在完成百度图片爬取时我对.format()用法和urllib.parser下的quote用法不熟悉,故以转载链接补充二者。
format:[](https://www.cnblogs.com/hdk1993/p/8428772.html)
quote:[](https://blog.csdn.net/weixin_43411585/article/details/89067127)
成果展示>>>
https://img2020.cnblogs.com/blog/2036189/202008/2036189-20200817145323592-2049625573.png

浙公网安备 33010602011771号