文章目录
前言
本文主要是介绍python爬取静态网页图片的方法,可以爬取多个网页,是通用的。目前动态网页图片爬取的方法还没有实现。静态网页和动态网页区别:
静态网页图片:图片url地址直接显示在网页源代码里面。
动态网页图片:如“百度图片”的网页,动态网页图片的URL没有直接暴露在源代码中,图片是存放在静态资源文件中,例如:static或image文件夹中。
一、方法介绍
1.方法参考链接
https://jingyan.baidu.com/article/46650658d73272f548e5f87c.html
https://www.jb51.net/article/141513.htm
2.实现原理
整个代码的实现原理,实际上挺简单的,就是根据import urllib.request的urlopen(url)方法获取到网页链接的源码,当然一般情况下先要添加用户代理,模拟人访问网站,防止网站的反爬虫。具体方法如下:requs=urllib.request.Request(url)
requs.add_header('User-Agent','user_agent')
urllib.request.urlopen(requs)
然后使用BeautifulSoup方法格式化源码,最后根据格式化的代码查找对应的标签,然后找出对应的值(调用BeautifulSoup的查找方法),也就是图片的下载地址url,最后再使用方法,把图片给下载下来。BeautifulSoup官方中文版链接:
https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
这里最关键的一点就是确定那个图片的下载地址,不同的网站那个获取图片的地址的方法可能不一样,我写的这个的话,普通的有好多网站应该是可以通用的,到时候实在不行可以根据对应的那个网站代码,然后修改一下获取图片下载地址的方法。
3.其他方法介绍
Beautiful Soup的语法
html网页—>创建BeautifulSoup对象—>搜索节点 find_all()/find()—>访问节点,名称,属性,文字等……
其实除了根据标签值找到对应的图片下载链接,还可以使用正则表达式。
二、使用步骤
0.参考博客
最开始参考的博客:
以关键语句搜索找到的博客感觉很棒:python获得某html页面所有图片链接
https://blog.csdn.net/Drifter_Galaxy/article/details/104886684
1.引入库
导入需要使用到的类库:
import urllib.request # 导入用于打开URL的扩展库模块
import urllib.parse
from bs4 import BeautifulSoup # 之前的方法没有用到此方法,改进的代码需要使用此模块方法
import re # 导入正则表达式模块
2.遇到的问题
#下面几行是相关问题以及参考链接:这里我就不贴具体解决办法了,需要的自己去往相应页面查看
#urllib.error.HTTPError: HTTP Error 418: 需要添加用户代理:user-agent
#IndexError: list assignment index out of range的解决方法:
https://blog.csdn.net/qq_44768814/article/details/88614393
#python 通过链接下载图片或者包:
https://blog.csdn.net/qq_34783484/article/details/95314582
#Positional argument after keyword argument:
https://blog.csdn.net/swy_swy_swy/article/details/106290505
#python,如何获取字符串中的子字符串,部分字符串:
https://www.cnblogs.com/chuanzhang053/p/10006768.html
#Python中用startswith()函数判断字符串开头的教程:
https://www.jb51.net/article/63589.htm
#TypeError: 'int' object is not callable:这个问题没有解决好,感觉并不是这个原因,我觉得是startswith()方法里面多写了参数
https://blog.csdn.net/gaifuxi9518/article/details/81193296
#AttributeError: 'str' object has no attribute 'startwith':注意函数名称书写要正确!将startwith改为startswith即可!
https://blog.csdn.net/u010244992/article/details/104554484/
#python中,获取字符串的长度: 通过方法 len(str) 获取
https://www.cnblogs.com/chuanzhang053/p/10006856.html
#UnicodeEncodeError: 'ascii' codec can't encode characters in position 38-43: 这个问题我没有解决,我直接没有管(报错原因是我输入的爬取地址里面包含了中文)
https://blog.csdn.net/zhangxbj/article/details/44975129
#python 爬虫爬取百度图片:无法爬取百度图片的原因是百度图片网页是动态的,而我写的方法是爬取静态网页的
3.使用到的图片下载地址
# 定义url
# url = "https://movie.douban.com/top250"
# url = "https://movie.douban.com/chart"
#//img.ivsky.com/img/tupian/li/202011/30/laju-005.jpg 下面这个页面存在相对路径(不包含http:请求头,需要添加才能爬取成功
#url = "https://www.ivsky.com/tupian/zhiwuhuahui/"
#/static/res/pichp/imgs/picLogo.gif下面这个页面包含了不是以http开头的<img src链接
# url = "http://pic.yxdown.com/list/0_0_1.html"
# url = "https://m.baidu.com/sf/vsearch?pd=image_content&word=森林图片下载&tn=vsearch&atn=page"
#下面的一个URL爬取不了图片链接,因为那个是百度的动态页面,图片链接没有直接暴露,我现在写的这个方法只能爬取静态页面
# url = "https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&ie=gb18030&word=%CD%BC%C6%AC%CF%C2%D4%D8&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=000000"
4.所有代码
该处使用的url是需要爬取的图片网页链接。里面的注释嫌烦可以直接删除,我保留是为了方便查看,知道写的过程。
#! author: fenggbinn
#@ date: 2021-06-09下午-2021-06-10 00:21凌晨
# 这个是从交实验开始写的一个方法页面,写的过程中在网上查询了很多问题,一个一个的解决
# 感觉这个网站爬取图片挺好:https://www.ivsky.com/tupian/dongwutupian/
# 爬取的时候遇到了需要使用User-agent,百度方法找了半天,结果发现是自己浏览器的查找user-agent有问题
#下面几行是相关问题以及参考链接
#IndexError: list assignment index out of range的解决方法:https://blog.csdn.net/qq_44768814/article/details/88614393
#python 通过链接下载图片或者包:https://blog.csdn.net/qq_34783484/article/details/95314582
#Positional argument after keyword argument: https://blog.csdn.net/swy_swy_swy/article/details/106290505
#python,如何获取字符串中的子字符串,部分字符串: https://www.cnblogs.com/chuanzhang053/p/10006768.html
#Python中用startswith()函数判断字符串开头的教程: https://www.jb51.net/article/63589.htm
#TypeError: 'int' object is not callable:https://blog.csdn.net/gaifuxi9518/article/details/81193296 这个问题没有解决好,感觉并不是这个原因,我觉得是startswith()方法里面多写了参数
#AttributeError: 'str' object has no attribute 'startwith':https://blog.csdn.net/u010244992/article/details/104554484/ 注意函数名称书写要正确!将startwith改为startswith即可!
#python中,获取字符串的长度: https://www.cnblogs.com/chuanzhang053/p/10006856.html 通过方法 len(str) 获取
#UnicodeEncodeError: 'ascii' codec can't encode characters in position 38-43: https://blog.csdn.net/zhangxbj/article/details/44975129 这个问题我没有解决,我直接没有管(报错原因是我输入的爬取地址里面包含了中文)
#python 爬虫爬取百度图片:无法爬取百度图片的原因是百度图片网页是动态的,而我写的方法是爬取静态网页的
import urllib.request # 导入用于打开URL的扩展库模块
import urllib.parse
from bs4 import BeautifulSoup # 之前的方法没有用到此方法,改进的代码需要使用此模块方法
import re # 导入正则表达式模块
#copy from web
def open_url(url):
req = urllib.request.Request(url) # 将Request类实例化并传入url为初始值,然后赋值给req
# 添加header,伪装成浏览器
# req.add_header('User-Agent',
# 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 '
# 'Safari/537.36 SE 2.X MetaSr 1.0')
#第二个请求头#urllib.error.HTTPError: HTTP Error 418: I'm a teapot
req.add_header('User-Agent',
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36')
# 访问url,并将页面的二进制数据赋值给page
page = urllib.request.urlopen(req)
# 将page中的内容转换为utf-8编码
html = page.read().decode('utf-8')
return html
#自己写的获取图片链接的方法
def get_allImgUrl(html):
imgurl = BeautifulSoup(html,"html.parser")
imall=[]
#测试获取所有图片链接,可根据具体网站修改相应的方法或者添加判断语句
for imgu in imgurl.find_all('img'):
im=imgu.get('src')
print(im+'000000000000')
#判断链接是否有效
if im.startswith('http'):
imall.append(im)
pass
elif im.startswith('//'):
imall.append('http:'+im)
# imall.append(im)
# print(im)
# print(imgu)
#测试是否获取到图片链接
for j in imall:
print(j+'9999999999')
pass
return imall
#根据copy from web 方法改写的图片下载方法
#imall是获取到的所有图片的链接地址
def downloadPictures(imall):
# 循环遍历列表的每一个值
for img in imall:
# 以/为分隔符,-1返回最后一个值
filename = img.split("/")[-1]
#添加判断图片链接//img.ivsky.com/img/tupian/li/202011/30/laju-005.jpg
#有的图片前面可能添加了//双斜杠
#上面那个没有什么问题,不需要判断,需要判断的是有的没有http: 开头,是用的静态文件,比如logo相关图片,才需要判断,不然会报错,这个判断应该写在添加链接到列表时
#当我再次测试,发现//双斜杠还是需要判断,不然它读取之后不会识别为链接,在上面判断了
# if img.startswith('//'):
# img=img[2:len(img)+1]
# print(img)
# pass
# else:
# print('fale')
'''
函数:startswith()
作用:判断字符串是否以指定字符或子字符串开头
一、函数说明
语法:string.startswith(str, beg=0,end=len(string))
或string[beg:end].startswith(str)
参数说明:
string: 被检测的字符串
str: 指定的字符或者子字符串。(可以使用元组,会逐一匹配)
beg: 设置字符串检测的起始位置(可选)
end: 设置字符串检测的结束位置(可选)
如果存在参数 beg 和 end,则在指定范围内检查,否则在整个字符串中检查
返回值
如果检测到字符串,则返回True,否则返回False。默认空字符为True
函数解析:如果字符串string是以str开始,则返回True,否则返回False
'''
request_download(img, savepath="d:/test/t2",filename=filename)
# # 访问each,并将页面的二进制数据赋值给photo
# photo = urllib.request.urlopen(img)
# w = photo.read()
# # 打开指定文件,并允许写入二进制数据
# f = open('D:/test/' + filename, 'wb')
# # 写入获取的数据
# f.write(w)
# # 关闭文件
# f.close()
# print(filename + " have been download...")
#网上其他地方找的根据链接下载代码(进行改写)
def request_download(IMAGE_URL,savepath,filename):
import requests
r = requests.get(IMAGE_URL)
with open(savepath+"/"+filename, 'wb') as f:
f.write(r.content)
f.close()
print(filename+": downloaded")
#copy from web (下面这个方法是之前的,后面我改进代码之后,这个方法没有使用了,这个方法很死板,只能爬取固定的页面,我改进之后的代码可以爬取多个不同的静态页面
def get_img(html):
# [^"]+\.jpg 匹配除"以外的所有字符多次,后面跟上转义的.和png
p = r'(http.:[\S]*?.(jpg|jpeg|png|gif|bmp|webp))'
# 返回正则表达式在字符串中所有匹配结果的列表
imglist = re.findall(p, html)
print("List of Img: " + str(imglist))
# 循环遍历列表的每一个值
for img in imglist:
# 以/为分隔符,-1返回最后一个值
filename = img[0].split("/")[-1]
# 访问each,并将页面的二进制数据赋值给photo
photo = urllib.request.urlopen(img[0])
w = photo.read()
# 打开指定文件,并允许写入二进制数据
f = open('D:/test/' + filename, 'wb')
# 写入获取的数据
f.write(w)
# 关闭文件
f.close()
print(filename + " have been download...")
# 该模块既可以导入到别的模块中使用,另外该模块也可自我执行
if __name__ == '__main__':
# 定义url
# url = "https://movie.douban.com/top250"
# url = "https://movie.douban.com/chart"#urllib.error.HTTPError: HTTP Error 418: I'm a teapot
url = "https://www.ivsky.com/tupian/zhiwuhuahui/"#//img.ivsky.com/img/tupian/li/202011/30/laju-005.jpg 这个页面存在相对路径(不包含http:请求头,需要添加才能爬取成功
# url = "http://pic.yxdown.com/list/0_0_1.html"#/static/res/pichp/imgs/picLogo.gif000000000000这个页面包含了不是以http开头的<img src链接
# url = "https://m.baidu.com/sf/vsearch?pd=image_content&word=森林图片下载&tn=vsearch&atn=page"
#下面的一个URL爬取不了图片链接,因为那个是百度的动态页面,图片链接没有直接暴露,我现在写的这个方法只能爬取静态页面
# url = "https://image.baidu.com/search/index?tn=baiduimage&ct=201326592&lm=-1&cl=2&ie=gb18030&word=%CD%BC%C6%AC%CF%C2%D4%D8&fr=ala&ala=1&alatpl=adress&pos=0&hs=2&xthttps=000000"
# 将url作为open_url()的参数,然后将open_url()的返回值作为参数赋给get_img()
# get_img(open_url(url))
# get_allImgUrl(open_url(url))
downloadPictures(get_allImgUrl(open_url(url)))
print("all over...")
总结
本文章主要是使用python批量爬取网页的图片,直接下载到本地。当然学会了,应该灵活运用,不只是可以根据标签找到图片下载的地址,要下载其他的内容,也可以直接替换一下相应的内容就可以了。
这个文章也只是我初接触python爬虫,应该还有很多没有写好的地方,有的方法并不是最好的,大家有什么建议的话可以直接留言。
其他
1.CSDN文章字体颜色
写这篇文章突然发现,CSDN上可以使用《<font color=#999AAA’>’》调节字体颜色。
color=后面的16进制颜色码可以根据自己喜好更改。
贴一个16进制颜色码参考链接:
https://blog.csdn.net/shakespeare001/article/details/7816022
2.博客链接存放
这篇文章中的所有链接我都放到代码块里面了,方便审核,链接太多,经常审核出问题。