欢迎关注微信公众号:老夫撸代码
微信小程序写多了,老夫也换换口味,写点儿其它的教程
10分钟教程:如何使用Python批量爬取网页的图片资源
敲黑板,知识点:
正则表达式、网络请求、读写文件、SSL认证、操作文件夹、Base64解析图片
为什么出这个教程?
最近公司业务需要开发一些基于微信小程序的营销类工具,比如:砸金蛋、大转盘、九宫格抽奖等等,所以老夫参考了一些网赚平台的H5营销工具,使用Taro来开发小程序端的营销工具。
老夫先将此网址贴出来,链接如下:
https://activity.tuiayonghu.com/activity/index?id=9150&slotId=193506&login=normal&appKey=uuNX4GQ6Xoi9mNG2yZcz3eYBRf1&deviceId=212a63c1-0fb1-4f9b-8fcf-70bfb1a6df94&dsm=1.193506.0.0&tenter=SOW&subActivityWay=2&tck_rid_6c8=0ad021cejrhq8cb9-6019810&tck_loc_c5d=tactivity-9150&dcm=401.193506.0.0&&tenter=SOW
手机浏览器效果如下图:
老夫只是想借用一下对方的图片资源,一般获取一个网页的图片资源有以下几种方式:
- 在当前页面右键-另存为,就会将当前页面的样式文件、图片资源、字体资源等下载到本地
- 通过F12,打开开发者工具 - Sources - 右键 - Open in new tab ,在新页面中另存为即可
上述1方法一般是大家用的方式,但是仅限于当前页面请求过的图片资源,如果是通过js加载的资源是获取不到的。
上述2方法不推荐,费时间。
上面讲到的两种方法都不适用,因为这个链接只支持手机打开,在pc上面打开会跳页的,所以我们通过python来获取网页的图片资源。
没有什么事情是通过写程序办不到,如果办不到,请多写几个程序!
以下涉及到的代码使用的是python3的语法
人生苦短,我用Python
这里我用大概138行的python来实现爬取图片资源并保存到本地的过程。
为什么不用其它语言来实现而用 python 来实现?
因为python入门低,而且各种类库用的那个爽。
第一步:通过url获取目标文件源码
我们通过python自带的标准库 urllib.request 来构造请求,并获取请求到的内容,并把这些内容写入到index.html文件中,示例代码如下:
'''
author:老夫撸代码
wechat:cxyzxh1388
获取目前url的源文件
'''
def getIndex():
#目标url
url = "https://activity.tuiayonghu.com/activity/index?id=9150&slotId=193506&login=normal&appKey=uuNX4GQ6Xoi9mNG2yZcz3eYBRf1&deviceId=212a63c1-0fb1-4f9b-8fcf-70bfb1a6df94&dsm=1.193506.0.0&tenter=SOW&subActivityWay=2&tck_rid_6c8=0ad021cejrhq8cb9-6019810&tck_loc_c5d=tactivity-9150&dcm=401.193506.0.0&&tenter=SOW"
request = urllib.request.Request(url)
#去掉ssl认证
ssl._create_default_https_context = ssl._create_unverified_context
with urllib.request.urlopen(request) as f:
html = f.read()
'''因为html读出来的是二进制,因此写入index.html也必须以二进制的形式'''
with open('index.html','wb') as fb:
fb.write(html)
currpath = os.getcwd()
if not os.path.exists(currpath+'/css'):
os.mkdir(currpath + '/css')
if not os.path.exists(currpath+'/images'):
os.mkdir(currpath + '/images')
return os.getcwd()+'/index.html'
代码解析:
- urllib读取url的时候,返回的是二进制格式的内容,因此保存到文件种也必须是以wb的方式写入
- 在保存index.html的同时,新建css文件夹和images文件夹
有一点儿需要注意的是:
如果url是以https开头的,我们需要将ssl认证关闭,代码如下:
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
第二步:处理index.html源码中的图片资源
通过分析生成的index.html的文件结构,我们发现并没有任何一个显式声明的img标签存在于html的标签当中,更多的是将图片资源的链接拼接到js代码中:
"value":"//yun.tuitiger.com/mami-media/img/1vxv3dun0w.png"
"image":"//yun.tuiayonghu.com/mami-media/img/el1bddtppl.png"
先上代码:
'''
获取直接页面的图片资源
'''
def getIndexImage(path):
soup = BeautifulSoup(open(path), 'lxml')
'''获取页面中img标签'''
imgs = soup.find_all('img')
if len(imgs) > 0:
#todo 保存Url图片,因为此链接的源码页面中并没有img标签,所以这里不做处理
print()
'''获取js变量中的img路径'''
with open(path) as p:
content = p.read()
imglist = re.findall('("image":[^,]*,)',content)
print(imglist)
for img in imglist:
arr = img.split(':')
url = 'http:'+arr[1][1:-2]
saveImage(url)
valuelist =re.findall('("value":"//yun[^,]*,)',content)
print(valuelist)
for img in valuelist:
arr = img.split(':')
url = 'http:'+arr[1][1:-2]
saveImage(url)
'''将url图片路径保存为图片'''
def saveImage(url):
name = url[url.rindex('/')+1:]
with urllib.request.urlopen(url) as i:
content = i.read()
with open(os.getcwd()+'/images/'+name,'wb') as f:
f.write(content)
print('保存图片:'+name+'\n')
代码解析:
- 上述代码主要用到一个类库 BeautifulSoup,它是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.
-
imgs = soup.find_all('img')
此方法就是在当前文档结构中查找所有显式声明的img标签 - 上述代码 12 ~ 25 行代码是通过正则表达式将所有拼接到js中的图片路径找到,并且保存到images的文件夹中。
第三步:保存index.html中的css文件
在前两步,我们已经将index.html中涉及到的图片资源都已保存下来,但是那些通过js加载的图片,还未处理。
我们先处理隐藏到css中的图片资源。
css中的图片资源分为两种:
- 图片资源链接
- base64格式的图片资源
上述 1 中的图片资源很好处理,我们通过正则表达式先将这些图片链接筛选处理,然后再通过模拟请求,保存到本地,代码如下:
#保存css文件
def dealCss(path):
soup = BeautifulSoup(open(path), 'lxml')
links = soup.find_all('link', attrs={'href': re.compile('.css')})
'''
保存css文件到文件夹中
'''
list = []
for link in links:
href = 'http:' + link['href']
name = href[href.rindex('/') + 1:]
request = urllib.request.Request(href)
with urllib.request.urlopen(request) as u:
css = u.read()
with open(os.getcwd()+'/css/'+name,'wb') as f:
f.write(css)
'''
通过正则表达式提取base64数据和图片路径
'''
dirss = os.listdir(os.getcwd()+'/css')
for dir in dirss:
with open(os.getcwd()+'/css/'+dir) as f:
content = f.read()
reglist = re.findall('(url\([^\)]*\);)',content)
for i in reglist:
real = i[i.index('(')+1:i.rindex(')')]
if real.startswith("//"):
saveImage('http:'+real)
else:
saveBase64(real)
代码解析:
- 3~16行代码是获取index.html中显式声明的css文件,并保存。
- 20~28行代码是通过对已保存的css文件,进行正则表达式找到图片的路径。因为在css中只能通过background-image:url(*****)来加载图片,url中即可以加载图片又可以加载base64编码的图片数据,所以我们需要分开处理。
- '(url([^)]);)'* 这个正则表达式获取了所有加载的图片
- i[i.index('(')+1:i.rindex(')')] 是获取了url里面包括的数据
- real.startswith("//") 判断是否为图片链接
第四步:解码base64格式的图片并保存
css中base64图片的格式为如下:
background-image: url("data:image/png;base64,iVBORw0KGgo=...");
其中iVBORw0KGgo=...才是base64编码的数据,我们需要把这部分数据解码,然后保持到图片文件中。
'''将base64的编码转换为图片格式'''
def saveBase64(code):
rc = re.search('data:image\/[a-z]+;',code).group()
ext = '.'+rc[rc.rindex('/')+1:-1]
name = ''.join(random.sample(['z','y','x','w','v','u','t','s','r','q','p','o','n','m','l','k','j','i','h','g','f','e','d','c','b','a'], 8))
seq = re.search('data:image\/[a-z]+\;base64,',code).span()
print(seq)
newcode = code.replace(code,code[seq[1]:-1])
print(newcode+'\n')
with open(os.getcwd()+'/images/'+name+ext,'wb') as f:
if len(newcode) % 4 != 0: # check if multiple of 4
while len(newcode) % 4 != 0:
newcode = newcode + "="
req_str = base64.b64decode(newcode)
else:
req_str = base64.b64decode(newcode)
f.write(req_str)
代码解析:
- data:image/png表示当前的图片格式是png
- 4~5 行代码表示获取图片的扩展名和生成随机图片名称
- 6~8 行代码获取base64的数据格式
- 10~17 行代码将base64的数据格式解码并且保存到图片文件中。
......
关注微信公众号:老夫撸代码 回复数字 1009
获取完整代码
网友评论