飞道的博客

Python网络爬虫数据采集实战:Requests和Re库

487人阅读  评论(0)

​    熟悉爬虫的基本概念之后,我们可以直接开始爬虫实战的学习,先从Python的requests库即re库入手,可以迅速“get”到python爬虫的思想以及流程,并且通过这两个库就可以建立一个完整的爬虫系统。

 

目录

一、requests库

    1.简介

    2.入门测试

    3.主要方法

二、re库

    1.简介

    2.入门测试

    3.主要方法


一、requests

    1.简介

    Requests是用Python语言编写的,基于urllib3来改写的,采用Apache2 Licensed 来源协议的HTTP库。它比urllib更加方便,可以节约我们大量的工作,完全满足HTTP测试需求。在日常使用中我们绝大部分使用requests库向目标网站发起HTTP请求。

    通过上图官网对requests的介绍可知此库的强大之处:Requests是唯一适用于Python的Non-GMO HTTP库,可供人类安全使用。

    2.入门测试

    我们首先通过代码实例测试一下Requests库的使用情景。首先本文采用配置环境为win10+anaconda3+Python3.7.4,直接在终端运行:

pip install requests

    如果出现以下字样即代表安装完成。

    urllib 库中的urlopen()方法实际上是以GET方式请求网页,而requests 中相应的方法就是get()。在Python中运行以下代码:


  
  1. import requests
  2. # 以get方式获取百度官网源代码
  3. res = requests.get( "https://www.baidu.com")
  4. # 获取返回类型
  5. print(type(res))
  6. # 获取状态码
  7. print(res.status_code)
  8. # 获取返回源代码内容类型
  9. print(type(res.text))
  10. # 获取前15字符
  11. print((res.text)[: 15])
  12. # 获取cookies
  13. print(res.cookies)

输出结果为:


  
  1. < class 'requests.models.Response'>
  2. 200 # 状态码200代表响应正常
  3. <class 'str'>
  4. <!DOCTYPE html>
  5. <RequestsCookieJar[<Cookie BDORZ=27315 for .baidu.com/>
 

3.主要方法

    requests库的主要方法有以下7种,接下来就几种常用方法进行简单介绍。

方法

说明

requests.get()

获取HTML网页的主要方法,对应于HTTP的GET

requests.head()

获取HTML网页头信息的方法,对应于HTTP的HEAD

requests.post()

向HTML网页提交POST请求的方法,对应于HTTP的POST

requests.put()

向HTML网页提交PUT请求的方法,对应于HTTP的PUT

requests.patch()

向HTML网页提交局部修改请求,对应于HTTP的PATCH

requests.delete()

向HTML页面提交删除请求,对应于HTTP的DELETE

    get方法是我们通常最常用的方法。输入如下代码对网站提交get请求:


  
  1. import requests
  2. res = requests.get( "http://httpbin.org/get")
  3. print(res.text)

    输出结果为:


  
  1. ​{
  2. "args": {},
  3. "headers": {
  4. "Accept": "*/*",
  5. "Accept-Encoding": "gzip, deflate",
  6. "Host": "httpbin.org",
  7. "User-Agent": "python-requests/2.22.0",
  8. "X-Amzn-Trace-Id": "Root=1-5e5dd355-96131363cf818957b8e7b67d"
  9. },
  10. "origin": "171.112.101.74",
  11. "url": "http://httpbin.org/get"
  12. }

由上述输出可知响应结果包含请求头、URL和IP等信息。而如果我们想在get请求中输入参数信息,则需要设置params参数:


  
  1. import requests
  2. data = {
  3. 'building': "zhongyuan",
  4. 'nature': "administrative"
  5. }
  6. res = requests.get( "http://httpbin.org/get",params=data)
  7. print(res.text)


    输出内容为:


  
  1. {
  2. "args": {
  3. "building": "zhongyuan",
  4. "nature": "administrative"
  5. },
  6. "headers": {
  7. "Accept": "*/*",
  8. "Accept-Encoding": "gzip, deflate",
  9. "Host": "httpbin.org",
  10. "User-Agent": "python-requests/2.22.0",
  11. "X-Amzn-Trace-Id": "Root=1-5e5dd4db-f0568e98f3350cae8998968a"
  12. },
  13. "origin": "171.112.101.74",
  14. "url": "http://httpbin.org/get?building=zhongyuan&nature=administrative"
  15. }

由上可知在get请求中成功将参数传递进去。此外,上述返回格式不仅是字符串格式,还是json文件格式,因此我们可以通过Python中json库对返回信息进行解析:


  
  1. import requests
  2. res = requests.get( "http://httpbin.org/get")
  3. print(type(res.text))
  4. print(res.json())
  5. print(type(res.json()))

输出结果为:


  
  1. < class 'str'>
  2. {'args': {}, 'headers': { 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'python-requests/2.22.0', 'X-Amzn-Trace-Id': 'Root=1-5e5dd5e5-b195baec1c11b51c03eee96c'}, 'origin': '171.112.101.74', 'url': 'http://httpbin.org/get'}
  3. < class 'dict'>

为了将 Requests 发起的 HTTP 请求伪装成浏览器,我们通常是使用headers关键字参数。headers 参数同样也是一个字典类型。具体用法见以下代码:


  
  1. import requests
  2. headers = {
  3. 'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
  4. }
  5. res = requests.get( "http://httpbin.org/get",headers=headers)
  6. print(res.text)

输出结果如下,可以看出在headers参数中我们的"User-Agent"发生了改变,而不再是之前暴露的requests了,这对于一些对爬虫有限制的网站似乎很有用。


  
  1. {
  2. "args": {},
  3. "headers": {
  4. "Accept": "*/*",
  5. "Accept-Encoding": "gzip, deflate",
  6. "Host": "httpbin.org",
  7. "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36",
  8. "X-Amzn-Trace-Id": "Root=1-5e5dd68c-e185889878974c88aff8d704"
  9. },
  10. "origin": "171.112.101.74",
  11. "url": "http://httpbin.org/get"
  12. }

data 参数通常结合 POST 请求方式一起使用。如果我们需要用 POST 方式提交表单数据或者JSON数据,我们只需要传递一个字典给 data 参数。


  
  1. import requests
  2. data = {
  3. 'user': 'admin',
  4. 'pass': 'admin'
  5. }
  6. res = requests.post( 'http://httpbin.org/post', data=data)
  7. print(res.text)

获取结果如下:


  
  1. {
  2. "args": {},
  3. "data": "",
  4. "files": {},
  5. "form": {
  6. "pass": "admin",
  7. "user": "admin"
  8. },
  9. "headers": {
  10. "Accept": "*/*",
  11. "Accept-Encoding": "gzip, deflate",
  12. "Content-Length": "21",
  13. "Content-Type": "application/x-www-form-urlencoded",
  14. "Host": "httpbin.org",
  15. "User-Agent": "python-requests/2.22.0",
  16. "X-Amzn-Trace-Id": "Root=1-5e5dd775-932576d4bdcad64891fb54fa"
  17. },
  18. "json": null,
  19. "origin": "171.112.101.74",
  20. "url": "http://httpbin.org/post"
  21. }

我们使用代理发起请求,经常会碰到因代理失效导致请求失败的情况。因此,我们对请求超时做下设置。当发现请求超时,更换代理再重连。


  
  1. # 设置3s超时断连
  2. res = requests.get(url, timeout= 3)
  3. # 传入元组参数,分别设置断连超时时间与读取超时时间
  4. response = requests.get(url, timeout=( 3, 30))

二、re库

    1.简介

    正则表达式是一个特殊的字符序列,能方便的检查一个字符串是否与某种模式匹配。re模块使得python拥有全部的正则表达式功能。在爬虫自动化程序中,re库充当信息提取的角色,通过re库我们可以从源代码中批量精确匹配到想要的信息。

    2.入门测试

    开源中国提供的正则表达式匹配网站可以供我们很好的练手测试(网址:https://tool.oschina.net/regex/#)。下文我们先输入一段测试文本,再选择匹配Email地址,正则表达式为:[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?

    是不是像一串“乱码”?实际上这里面每一个“乱码”都有具体的意义,具体可参照下面的对照:


  
  1. \w 匹配字母数字及下划线
  2. \W 匹配f非字母数字下划线
  3. \s 匹配任意空白字符,等价于[\t\n\r\f]
  4. \S 匹配任意非空字符
  5. \d 匹配任意数字
  6. \D 匹配任意非数字
  7. \A 匹配字符串开始
  8. \Z 匹配字符串结束,如果存在换行,只匹配换行前的结束字符串
  9. \z 匹配字符串结束
  10. \G 匹配最后匹配完成的位置
  11. \n 匹配一个换行符
  12. \t 匹配一个制表符
  13. ^ 匹配字符串的开头
  14. $ 匹配字符串的末尾
  15. . 匹配任意字符,除了换行符,re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
  16. [....] 用来表示一组字符,单独列出:[amk]匹配a,m或k
  17. [^...] 不在[]中的字符:[^abc]匹配除了a,b,c之外的字符
  18. * 匹配 0个或多个的表达式
  19. + 匹配 1个或者多个的表达式
  20. ? 匹配 0个或 1个由前面的正则表达式定义的片段,非贪婪方式
  21. {n} 精确匹配n前面的表示
  22. {m,m} 匹配n到m次由前面的正则表达式定义片段,贪婪模式
  23. a|b 匹配a或者b
  24. () 匹配括号内的表达式,也表示一个组

    3.主要方法

  • match函数

    函数原型:match(pattern, string, flags=0)

    尝试从字符串的起始位置匹配一个模式,如果起始位置没匹配上的话,返回None


  
  1. import re
  2. content= "hello 123 4567 World_This is a regex Demo"
  3. result = re.match( '^hello\s\d\d\d\s\d{4}\s\w{10}.*Demo$',content)
  4. print(result)
  5. print(result.group()) #获取匹配的结果
  6. print(result.span()) #获取匹配字符串的长度范围

输出结果为:


  
  1. <re.Match object; span=( 0, 41), match= 'hello 123 4567 World_This is a regex Demo'>
  2. hello 123 4567 World_This is a regex Demo
  3. ( 0, 41)
 
  • 通用匹配

    上面的代码正则表达式太复杂,其实完全没必要这么做,因为还有一个万能匹配可以用,那就是.*(点星) 。其中.(点)可以匹配任意字符(除换行符),*(星)代表匹配前面的字符无限次,所以它们组合在一起就可以匹配任意字符了。因此我们可以使用下面的方式进行简化:


  
  1. content= "hello 123 4567 World_This is a regex Demo"
  2. result = re.match( '^hello.*Demo$',content)
  3. print(result)
  4. print(result.group())
  5. print(result.span())
 

    输出结果与前文相同:


  
  1. <re.Match object; span=( 0, 41), match= 'hello 123 4567 World_This is a regex Demo'>
  2. hello 123 4567 World_This is a regex Demo
  3. ( 0, 41)
 
  • 分组匹配

    为了匹配字符串中具体的目标,可以使用()进行分组匹配


  
  1. content= "hello 123 4567 World_This is a regex Demo"
  2. result = re.match( '^hello\s(\d+).*Demo$',content)
  3. print(result.group())
  4. print(result.group( 1))
 

    输出group组中的第一个结果:


  
  1. hello 123 4567 World_This is a regex Demo
  2. 123
 
  • 贪婪匹配

    简要说意思就是一直匹配,匹配到匹配不上为止。
 


  
  1. content= "hello 123 4567 World_This is a regex Demo"
  2. result = re.match( '^hello.*(?P<name>\d+).*Demo$',content)
  3. print(result.group())
  4. print(result.group( 1))
  5. print(result.groupdict())
 

    结果如下,最终结果输出的是7,出现这样的结果是因为被前面的.*给匹陪掉了,只剩下了一个数字,这就是贪婪匹配。


  
  1. hello 123 4567 World_This is a regex Demo
  2. 7
  3. { 'name': '7'}

    若要非贪婪匹配可以使用问号(?):


  
  1. content= "hello 123 4567 World_This is a regex Demo"
  2. result = re.match( '^hello.*?(?P<name>\d+).*Demo$',content)
  3. print(result.group())
  4. print(result.group( 1))
  5. print(result.groupdict())
 

    这样就可以得到123的结果了:


  
  1. llo 123 4567 World_This is a regex Demo
  2. 123
  3. { 'name': '123'}
 
  • 函数中添加匹配模式

  def match(pattern, string, flags=0) 第三个参数flags设置匹配模式

  re.I:使匹配对大小写不敏感

  re.L:做本地化识别匹配

  re.S:使.包括换行在内的所有字符

  re.M:多行匹配,影响^和$

  re.U:使用unicode字符集解析字符,这个标志影响\w,\W,\b,\B

  re.X:将正则表达式写得更易于理解

    例如通过设置匹配模式为re.I,使得使匹配对大小写不敏感:


  
  1. content= "heLLo 123 4567 World_This is a regex Demo"
  2. result = re.match( 'hello',content,re.I)
  3. print(result.group())

    结果如下,仍然会输出heLLo:

heLLo
  • search函数

    函数原型:def search(pattern, string, flags=0)

    扫描整个字符串,返回第一 个匹配成功的结果


  
  1. content= '''hahhaha hello 123 4567 world'''
  2. result = re.search( 'hello.*world',content)
  3. print(result.group())

    输出:

hello 123 4567 world
  • findall函数

    函数原型:def findall(pattern, string, flags=0)。搜索字符串,以列表的形式返回所有能匹配的字串


  
  1. content= '''
  2. <url>http://httpbin.org/get</url>
  3. <url>http://httpbin.org/post</url>
  4. <url>https://www.baidu.com</url>'''
  5. urls = re.findall( '<url>(.*)</url>',content)
  6. for url in urls:
  7. print(url)

以上命令将会输出所有符合条件的字符串即链接:


  
  1. http://httpbin.org/get
  2. http://httpbin.org/post
  3. https://www.baidu.com
  • sub函数

    函数原型:def subn(pattern, repl, string, count=0, flags=0)。替换字符串中每一个匹配的子串后返回替换后的字符串


  
  1. content= '''hello 123 4567 world'''
  2. str = re.sub( '123.*world', 'future',content)
  3. print(str)

    输出结果就会将123后面的内容替换成'future':

hello future
  • compile

    函数原型:def compile(pattern, flags=0)。将正则表达式编译成正则表达式对象,方便复用该正则表达式


  
  1. content= '''hello 123 4567 world'''
  2. pattern = '123.*world'
  3. regex = re.compile(pattern)
  4. str = re.sub(regex, 'future',content)
  5. print(str)

    输出结果同上文一样:

hello future

    有关requests库和re库的简单介绍和使用到此结束,下一篇将利用这两个库行网络数据爬取实战。基础知识可参考上篇:

Python网络爬虫数据采集实战:基础知识

 

 

 

 


转载:https://blog.csdn.net/qq_36936730/article/details/104633510
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场