1.查询数据
打开网页。
https://cn.bing.com/images/search?q=%E7%99%BE%E5%BA%A6%E5%9B%BE%E7%89%87&form=HDRSC2&first=1&cw=1585&ch=924
我们右键查看网页源代码,发现能找到我们需要的img衔接,但是这是一个动态网页。我们每次向下滑动网页,会发现图片更新,而图片更新一般伴随着异步请求。
并且我们打开控制台,如下图所示:
1.点击网络 2.点击Fetch/XHR
随着向下滑动:
下图红框异步请求次数增多。
我们将异步请求衔接,在另一个标签页打开。
发现这个异步请求的响应数据有我们需要的图片。
2.请求数据
我们在上面知道是一个动态网页之后,并且找到请求img的地址之后,我们是不是要探寻请求url的规律,发现是如何向下滚动,出现新的图片?
经过查找对比,发现这几个请求参数,新的请求会发生变化。
然后,我们通过对这几个参数修改进行请求,发现实际起作用的是first。也就是图片起始索引。
另外,q也就是我们搜索的数据进行url编码之后的东西。
3.解析数据
我们找到我们找寻的图片在哪里,但是发现请求响应的是一堆html + css + js代码,因此我们需要对其进行过滤,只找到我们需要的img的url。
我们在打开刚才的那个异步请求url,查看页面源代码。
将前端代码,粘贴到在线 HTML 格式化工具,HTML 代码美化工具 - 在线工具-wetools.com微工具
这个html格式化工具里面,格式化后,将格式化后的代码,粘贴到vscode里面。
我们查看代码发现,我们需要img的url,是在下图所示的层级结构里面:
更往上的html层级结构为:
因此我们的python爬虫代码可以这样写:
from lxml import etree
import requests
from fake_useragent import UserAgentif __name__ == '__main__':headers = {'User-Agent': UserAgent().random}url = "https://cn.bing.com/images/async?q=%e7%99%be%e5%ba%a6%e5%9b%be%e7%89%87&first=162" \"&count=35&cw=1177&ch=909&relp=35&apc=0&datsrc=I&layout=RowBased&mmasync=1&dgState=x*740_y*940_h*180_c*3_i*106_r*20&" \"IG=1EA071CC53E44DFA8101AF041D481594&SFX=4&iid=images.5563"# 请求响应数据html = requests.get(url=url,headers=headers).textp = etree.HTML(html)img_list = []# 解析响应数据ul_list = p.xpath('//ul[@data-row]') # 基准表达式for ul in ul_list:li_list = ul.xpath('.//li[@data-idx]')for li in li_list:img1_list = list(li.xpath('.//img[contains(@class,"mimg")]/@src'))img2_list = list(li.xpath('.//img[contains(@class,"cimg")]/@src'))for img1 in img1_list:img_list.append(img1)for img2 in img2_list:img_list.append(img2)print(img_list)
4.将图片保存到本地
我们将上述img 衔接,再次进行请求并下载到本地。
# 保存图片def save_images(self, img_list, dir_path, q):# 不存在,创建目录dir_path = dir_path + '/' + q + "/"if not os.path.exists(dir_path):os.makedirs(dir_path)i = 1for img in img_list:img_path = '{}{}-{}.jpg'.format(dir_path,q,i)self.save_image(img_path,img)i += 1# 保存图片def save_image(self,img_path,img):html = requests.get(url=img,headers=self.get_headers()).contentwith open(img_path,'wb') as f:f.write(html)
4.完整代码
from lxml import etree
import requests
from fake_useragent import UserAgent
from urllib import parse
import osclass BaiduSpider:def __init__(self):self.url = "https://cn.bing.com/images/async?q={}&first={}&count=35&cw=1177&ch=909" \"&relp=35&apc=0&datsrc=I&layout=RowBased&mmasync=1"# 获取请求头def get_headers(self):return {'User-Agent': UserAgent().random}# 获取响应数据def get_html(self, q, first):q = parse.quote(q)url = self.url.format(q, first)html = requests.get(url=url, headers=self.get_headers()).textreturn html# 解析响应数据def parse_html(self, html):p = etree.HTML(html)img_list = []# 基准表达式ul_list = p.xpath('//ul[@data-row]')for ul in ul_list:li_list = ul.xpath('.//li[@data-idx]')for li in li_list:img1_list = list(li.xpath('.//img[contains(@class,"mimg")]/@src'))img2_list = list(li.xpath('.//img[contains(@class,"cimg")]/@src'))for img1 in img1_list:img_list.append(img1)for img2 in img2_list:img_list.append(img2)print(img_list)return img_list# 保存图片列表def save_images(self, img_list, dir_path, q):# 不存在,创建目录dir_path = dir_path + '/' + q + "/"if not os.path.exists(dir_path):os.makedirs(dir_path)i = 1for img in img_list:img_path = '{}{}-{}.jpg'.format(dir_path,q,i)self.save_image(img_path,img)i += 1# 保存图片def save_image(self,img_path,img):html = requests.get(url=img,headers=self.get_headers()).contentwith open(img_path,'wb') as f:f.write(html)# 入口函数def run(self):q = input("请输入搜索内容:")first = int(input("请输入起始页数:"))dir_path = "../img"html = self.get_html(q, first)img_list = self.parse_html(html)self.save_images(img_list, dir_path, q)if __name__ == '__main__':bds = BaiduSpider()bds.run()