python3.8使用urllib的request方法和BeautifulSoup的格式化源码和查找方法爬取多个静态通用网站图片


前言

本文主要是介绍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.博客链接存放

这篇文章中的所有链接我都放到代码块里面了,方便审核,链接太多,经常审核出问题。

猜你喜欢

转载自blog.csdn.net/qq_43987149/article/details/117768963