概述:
第一次接触爬虫,从简单一点的爬取百度图片开始,话不多说,直接上手。
前期准备:
pip install requests
出现下图则安装成功
2.requests使用:
简单介绍一下requests的常用方法,基本知道一个requests.get()和requests.post()就行了。requests的返回值可以有多种形式输出,最常用的是".text"和".content",前者输出unicode,后者输出二进制。其他方法忘了可以查手册:requests快速上手
3.python正则模块使用:
python的正则模块是re,这里主要用到的函数是:
findall(pattern,str,re.S)
(re.S的意思是让"."可以匹配换行符,不然有些标签头和尾是分几行的,就会匹配失败)
正则表达式用到的是:
(.*?)
( ):表示这个内容是我们需要提取的
.*:表示匹配任意字符0-n次
?:表示非贪心,找到第一个就停下来
分析网页:
首先打开百度图片,输入我们想搜索的图片
点击搜索
按F12打开开发者工具,
1.点击开发者工具左上角的鼠标跟随;
2.鼠标移动到图片点击;
3.复制开发者工具里图片的地址。
在网页空白处,鼠标右键点击查看网页源代码
Ctrl+F打开搜索框,粘贴刚刚复制的图片地址
找到图片地址,发现有四个地址thumbURL,middleURL,hoverURL,objURL,我们用哪个呢,通过打开网页发现,objURL是最清晰的,所以我们选择用objURL(其他几个也行)
编写代码:
我们要用到2个包,一个是正则(re),一个是requests包
#-*- coding:utf-8 -*-
import re
import requests
复制搜索页面的网址
把网址粘过来,传入requests,写好正则表达式
url = 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1530020186092_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E5%B0%8F%E9%BB%84%E4%BA%BA'
html = requests.get(url).text
pic_url = re.findall('"objURL":"(.*?)",',html,re.S)
另外,还要写一个循环,加载多张图片,这里由于有些图片可能存在网址打不开的情况,加个5秒超时控制。
pic_url = re.findall('"objURL":"(.*?)",',html,re.S)
i = 0
for each in pic_url:
print each
try:
pic= requests.get(each, timeout=5)
except requests.exceptions.ConnectionError:
print '【错误】当前图片无法下载'
continue
再就是把网址保存下来,我们在事先在当前目录建立一个pictures目录,把图片都放进去,命名的时候,用数字命名
string = 'pictures\\'+str(i) + '.jpg'
fp = open(string,'wb')
fp.write(pic.content)
fp.close()
i += 1
全部代码如下:
#-*- coding:utf-8 -*-
import re
import requests
url = 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1530020186092_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E5%B0%8F%E9%BB%84%E4%BA%BA'
html = requests.get(url).text
pic_url = re.findall('"objURL":"(.*?)",',html,re.S)
i = 0
for each in pic_url:
print each
try:
pic= requests.get(each, timeout=5)
except requests.exceptions.ConnectionError:
print '【错误】当前图片无法下载'
continue
string = 'pictures\\'+str(i) + '.jpg'
fp = open(string,'wb')
fp.write(pic.content)
fp.close()
i += 1
但是这样只能下载一个网址的图片,能不能加一个关键字搜索呢?
又回来看网页,发现只要修改网址后面的关键字就能搜索不同的图片,只要在代码改url就能实现关键字搜索图片功能了
word = raw_input("Input key word: ")
url = 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1530013590757_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=' + word
result = requests.get(url)
最终代码:
# -*- coding:utf-8 -*-
import re
import requests
def dowmloadPic(html, keyword):
pic_url = re.findall('"objURL":"(.*?)",', html, re.S)
i = 0
t = 0
print('找到关键词:' + keyword + '的图片,现在开始下载图片...')
for each in pic_url:
print('正在下载第' + str(t + 1) + '张图片,图片地址:' + str(each))
t += 1
try:
pic = requests.get(each, timeout=5)
except requests.exceptions.ConnectionError:
print('【错误】当前图片无法下载')
continue
string = 'pictures\\' + keyword + '_' + str(i) + '.jpg'
# resolve the problem of encode, make sure that chinese name could be store
fp = open(string, 'wb')
fp.write(pic.content)
fp.close()
i += 1
if __name__ == '__main__':
word = input("请输入关键词: ")
url = 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1530013590757_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=' + word
result = requests.get(url)
dowmloadPic(result.text, word)
运行结果:
然而,运行之后发现只能下载30张图片,为什么呢?原来是ajax异步请求加载图片,百度图片一开始只加载30张图片,当我们往下滑动滚动条时,页面会动态加载1条json数据,每条json数据里面包含了30条信息,信息里面又包含了图片的URL,JavaScript会将这些url解析并显示出来。这样,每次滚动到底就又多出30张图片。
通过网上查询资料和请教同学,我又对之前的代码做了一些修改
再次分析网页:
再次进入小黄人搜索页面,打开开发者工具,点击Network--XHR--acjson?tn...(下拉网页可看到)--Headers
可以看到Query String Parameters里面的数据变化情况:
word:我们搜索的关键字
pn:当前加载的图片数量,每次增加30
rn:每页有30张图片
gsm:pn值的十六进制数,每次也是增加十进制的30
找到规律,那就好办了,继续写代码...
编写代码:
最终代码如下:
import requests
import os
def getManyPages(keyword,pages):
params=[]
for i in range(30,30*pages+30,30):
params.append({
'tn': 'resultjson_com',
'ipn': 'rj',
'ct': 201326592,
'is': '',
'fp': 'result',
'queryWord': keyword,
'cl': 2,
'lm': -1,
'ie': 'utf-8',
'oe': 'utf-8',
'adpicid': '',
'st': -1,
'z': '',
'ic': 0,
'word': keyword,
's': '',
'se': '',
'tab': '',
'width': '',
'height': '',
'face': 0,
'istype': 2,
'qc': '',
'nc': 1,
'fr': '',
'pn': i,
'rn': 30,
'gsm': '1e',
'1488942260214': ''
})
url = 'https://image.baidu.com/search/acjson'
urls = []
for i in params:
urls.append(requests.get(url,params=i).json().get('data'))
return urls
def getImg(dataList, localPath):
if not os.path.exists(localPath): # 如果给定的路径不存在文件夹,新建文件夹
os.mkdir(localPath)
x = 0
for list in dataList:
for i in list:
if i.get('thumbURL') != None:
print('正在下载:%s' % i.get('thumbURL'))
ir = requests.get(i.get('thumbURL'))
open(localPath + '%d.jpg' % x, 'wb').write(ir.content)
x += 1
else:
print('图片链接不存在')
if __name__ == '__main__':
word = input("请输入关键词: ")
j = input("请输入页数: ")
dataList = getManyPages(word,(int (j))) # 参数1:关键字,参数2:要下载的页数
getImg(dataList,'e:/Python/test1/pictures2/') # 参数2:指定保存的路径
运行结果:
总结:
终于完成第一个爬虫实践,过程不是很顺利,遇到不少问题,不过人生的快乐不就是在解决问题中寻找吗?做的项目也不是很难,结果可能还不够完美,但是这些都不是最重要的,最重要的,是过程中自己收获的经验和能力,这才是最宝贵的财富。也希望能和同学们一起探讨学习,共同进步。
附一张爬虫流程图: