python网络爬虫入门,urllib模块,爬取网页和图片,图片爬取正则表达式思路

一、urllib模块

1.urllib简介

在Python2版本中,有urilib和urlib2两个库可以用来发送request(请求)。而在Python3中,统一为urllib

urllib中包括了四个模块

-urllib.request可以用来发送request获取request结果

-urllib.parse用来解析和处理url

-urllib.error包含了urllib.request产生的异常

-urllib.rebotparse用来解析页面的robots.txt

 

2.爬取网页

现需要导入到用的模块,urllib.request

导入模块后,我们需要用到urlib.request.urlopen打开并爬取一个网页

读取内容常见的有3种方式:

-read()读取文件的全部内容,与readlines()不同的是,read()会把读取到的内容赋给一个字符串变量。

-readlines()读取文件的全部内容,readlines()会把读取的内容赋值给一个列表变量

-readline()读取文件的一行内容

 

实例:

import urllib.request

html=urllib.request.urlopen('http://www.baidu.com')

html.readline()

html.read(4096)

html.readlines()

可以体会一下输出结果

 

3.下载网络资源

urilib不仅可以下载网页,也可以下载其他网络资源

有些文件比较大,需要像读取文件一样,每次读取一部分数据,并依次存入文件中

  1. html = urlopen(http://www.baidu.com)   
  2.  
  3. with open('/tmp/baidu.html', 'wb') as fobj:
  4.        while True:
  5.                data = html.read(4096)
  6.                if not data:
  7.                   break
  8.                fobj.write(data) 
  9.        html.close()

 

4.数据编码

一般来说,URL标准中只允许一部分ASCII字符,比如数字、字母、部分符号

而其他的一些字符,比如汉字,是不合URl标准的,此时需要做编码

使用urllib.reqeust.quote()进行

urllib.request.quote('hello world!')                                   #字符编码

'hello%20world%21'

urllib.request.unquote(''hello%20world%21'')                 #字符反编码

hello world!

 

5.HTTP异常处理

如果访问的页面不存在或拒绝访问,程序将抛出异常,捕获异常需导入urllib.error模块

创建get_web3.py文件,实现访问不存在的路径和ban目录时,捕获404和403错误

,同时404错误打印“无此页面”,403错误打印“无权访问”,代码如下:

  1. import sys
  2. from urllib.request import urlopen
  3. from urllib.error import HTTPError                     #导入urllib.error模块,用HTTPError捕获异常信息
  4.  
  5. def get_web(url, fname):
  6.    try:
  7.       html = urlopen(url)                                       #打开网址时即可知道是否有异常,所以将本语句放入try语句
  8.    except HTTPError as e:                                  #捕获返回HTTPError类的实例e
  9.       print(e)
  10.       if e.code == 403:                                         #捕获异常状态码如果等于403
  11.           print('权限不足')                                      #输出'权限不足'
  12.       elif e.code == 404:                                     #捕获异常状态码如果等于404
  13.           print('没有那个地址')                              #输出'没有那个地址'
  14.       return                                                           #return后面代码均不执行
  15.         
  16.    open(fname, 'wb') as fobj:
  17.        while True:
  18.             data = html.read(4096)
  19.             if not data:
  20.                break
  21.            fobj.write(data)
  22.  
  23.        html.close()
  24.  
  25. if __name__ == '__main__':
  26.      get_web(sys.argv[1], sys.argv[2])

测试脚本执行:

访问不存在页面:

  1. [root@localhost day11]# python3 get_web.py http://127.0.0.1/abc/ /tmp/abc.html
  2. HTTP Error 404: Not Found
  3. 没有那个地址

访问ban目录:

  1. [root@localhost day11]# chmod 000 /tmp/abc.html
  2. [root@localhost day11]# python3 get_web.py http://127.0.0.1/ban/ /tmp/abc.html
  3. HTTP Error 403: Forbidden
  4. 权限不足

 

二、小实验--爬取网页并存为文件

 

要求:

编写一个get_web.py脚本,实现以下功能:

  1. 爬取的网页为http://www.baidu.com
  2. 保存的文件名为baidu.html

方案:

导入sys模块,用sys.argv方法获取get_web函数实参,让用户在命令行上提供http://www.baidu.com和/tmp/baidu.html两个参数,调用get_web函数实现如下功能:

  • 1.导入urllib模块,使用urllib模块的urlopen函数打开url(即网址),赋值给html
  • 2.以写方式打开/tmp/baidu.html文件
  • 3.以循环方式:
  • 读html获取的数据,保存到data
  • 将data写入/tmp/baidu.html
  • 4.关闭html

 

步骤一:编写脚本

  1. [root@localhost /]# vim get_web.py
  2. #!/usr/bin/env python3
  3.  
  4. import sys
  5. from urllib.request import urlopen
  6.  
  7. def get_web(url, fname):
  8.       html = urlopen(url)    #使用urllib模块的urlopen函数打开url,赋值给html
  9.  
  10.       with open(fname, 'wb') as fobj:
  11.               while True:
  12.                        data = html.read(4096)
  13.                        if not data:
  14.                           break
  15.                        fobj.write(data)
  16.  
  17.       html.close()
  18.  
  19. if __name__ == '__main__':
  20.        get_web(sys.argv[1], sys.argv[2])        #让用户在命令行上提供网址和下载数据保存位置

步骤二:测试脚本执行

  1. [root@localhost /]# python3 get_web.py http://baidu.com /tmp/baidu.html
  2. [root@localhost /]# cat /tmp/tedu.html
  3.  
  4. 执行cat命令可以看到/tmp/tedu.html文件中爬取到的内容

 

 

三、小实验2--爬取网页图片

 

我们上一个实验是爬取网页内容,那么大家有没有想过爬取网页当中的图片或视频文件?

这个实验主要是教大家爬取网页图片

首先回顾一下上面的实验,我们通过urllib.request.urlopen("网址")获取到网页内容

然后通过sys模块的存文件将获取到的网页内容存到文件中,如下

1.怎样获取图片?

要回答这个问题,大家应该回顾一下html,在html页面中,图片使用<img/>标签,在这个标签里有一个属性我src,而src里的链接,就是图片的保存路径,如图

那就可以这样解释,其实图片也相当于一个url,或者一个网页,我们可以使用urllib.request.urlopen("网址")来获取内容

2.所以我们可以按照这样的顺序来做这个实验:

  • 1.获取整个网页的内容,并保存到一个文件当中
  • 2.获取步骤1中的文件内容,并挑选出图片的路径(使用正则表达式)
  • 3.使用urllib请求图片内容,并下载到一个文件夹中
  • 4.查看图片

3.图片的后缀名:

常用图片后缀名有png和jpg,还有jpeg和gif

4.那么我们来分析一下图片的url

【python正则表达式讲解】https://blog.csdn.net/ck784101777/article/details/103253174

看下面图片的url

根据这一的格式,我们可以写出正则表达式

'http://[\w/-.]+\.(jpg|png|jpeg|gif)'             

分析一下这个表达,‘http://’这一部分是固定的,正则表达式直接照抄就行

那‘cdn.tmooc.cn/tmooc-web/css/img/’这一部分是变动的,那么就需要一些匹配符,仔细看这个路径出现了什么类型的字符,

是不是出现了:字符 '.'   '/'   '-',可能出现的还有数字,那根据正则表达式规则我们知道

\w匹配 任何 字母和数字,相当于[a-z A-Z 0-9 _ ] 注:还有下划线
[abc]匹配 ‘a’ 或 ‘b’ 或 ‘c’中任意一个
+匹配1个或多个的字符串

通过整合以上表达式,得出结果: [\w./-]+

这样我们就完成了“http://cdn.tmooc.cn/tmooc-web/css/img/tmooc-logo” 这个部分的内容

最后还有一个后缀,我之前说了图片的几种常见类型,那么可以写成:\.(jpg|png|jpeg|gif)

‘\.’匹配点,(jpg|png|jpeg|gif)匹配任意一种类型

得出的完整正则为'http://[\w/-.]+\.(jpg|png|jpeg|gif)'     

 

5.更多的图片url格式

有的人就问了,有些网站不是http开头的,而是https开头的

很简单,多给一个选择即可:'(http|https)://[\w/-.]+\.(jpg|png|jpeg|gif)'     

我们多找一点网站看看图片显示url格式

华为的:

淘宝的:

京东:

百度:

看到一个共同点没有,都没有http或https,为什么呢,因为这些网站都是用的相对路径,而不是绝对路径,怎么解决?

很好解决,看下面的正则表达式

(http|https)?:?//[\w./-]+\.(jpg|png|jpeg|gif)

我使用了一个?做处理

匹配0个或1个,为非贪婪方式

 

那么眼尖的人又看到了华为的图片url自有一个'/',怎么处理?

很简单 

+匹配1个或多个的字符串

那么我们最终的表达式如下: 

(http|https)?:?/+[\w./-]+\.(jpg|png|jpeg|gif)

完成了这一步,50%以上的网站你都可以爬取图片了

为什么说是50%?

如果我们用上面的表达式,则会匹配出这样的内容

//pic.cnblogs.com/face/979767/20180915094029.png

没有http或https,那有的人就说了,加一个判断,判断是否有http或https,没有就加上

可以加上,我们可以这样加,"https:"+"//pic.cnblogs.com/face/979767/20180915094029.png"

做一个字符串拼接

那问题就来了,有些url是只有一个'/'的,那我是怎么加呢,如果我强加就是这样的结果

"https:"+"/pic.cnblogs.com/face/979767/20180915094029.png"

只有一个'/',这样我们的urllib是获取不到图片内容的

那怎么办?

我们需要做一个二次正则匹配

匹配表达式:[\w]+[\w./-]+\.(jpg|png|jpeg|gif)

意思是获取'//'之后的内容

二次匹配后得到:pic.cnblogs.com/face/979767/20180915094029.png

那再做字符串拼接:"https://"+"pic.cnblogs.com/face/979767/20180915094029.png"

问题解决了下面看代码

#!/usr/bin/env python3
import sys
import re
import os
from urllib.request import urlopen

#获取图片链接(url)

def get_url(fname):                        
    cpatt = re.compile("(http|https)?:?/+[\w./-]+\.(jpg|png|jpeg|gif)")        #第一个正则用于匹配出图片链接
    cpatt2 = re.compile("[\w]+[\w./-]+\.(jpg|png|jpeg|gif)")                        #第二个正则用于过滤链接
    result = []                                                                                            #保存链接集
    with open(fname) as fobj:                                                                   #获取文件内容
        for line in fobj:                                                                                 #一行一行读
            m = cpatt.search(line)                                                                 #第一次匹配
            if m:                                                                                             #如果匹配到进一步处理
                m2 = cpatt2.search(m.group())                                               #第二次匹配,用于过滤链接
                https = "https://"+""+m2.group()                                              #   由于我不知道是http还是https,所以这里我们
                http  = "http://"+""+m2.group()                                                 #都保存到集合
                result.append(http)                                                                  #添加到集合
                result.append(https)      
    return result                            

#下载网页或图片信息

def get_web(url,fname):           
    try:
      html=urlopen(url)                                                                               #下载图片                                                              
      with open(fname,'wb') as f:                                                                #保存到文件
           while True:
               data = html.read(4096)
               if not data:
                  break
               f.write(data)
      html.close()
    except:
       return 

if __name__=="__main__":

    get_web('https://www.cnblogs.com/', '/mnt/tedu.html')                          #首先下载这个网页的内容,保存到文件                
    urls = get_url('/mnt/tedu.html')                                                 #再获取图片的链接保存到列表
    img_dir = '/mnt/images'                                                                           #存放文图片的目录
    if not os.path.exists(img_dir):                                                                  #没有该目录就创建
         os.mkdir(img_dir) 
    for url in urls:                                                                                           
         fname = os.path.join(img_dir, url.split('/')[-1])                                     #保存方式:目录/图片链接
         get_web(url, fname)                                                                           #下载图片     

执行脚本,成功后获取图片:

  1. [root@localhost day11]# python3 download.py 
  2. [root@localhost day11]# nautilus /tmp/images           #查看图片

 

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值