【python爬虫笔记】urllib模块、正则表达式、Beautiful Soup

目录

Python urllib 模块

urllib.request.urlopen()函数

urlopen() 返回对象的更多方法

urllib.Request() 类

urllib .request

urllib.parse

Python 正则表达式

正则表达式语法

re 库基本用法

原生字符串。

扫描二维码关注公众号,回复: 14815596 查看本文章

re.search 函数

re.match 函数

re.findall 函数

re.split 函数

re.finditer 函数

re.sub 函数

re 库其它函数

Beautiful Soup

BeautifulSoup 模块的对象说明

BeautifulSoup 对象

Tag 对象

Comment 对象



Python urllib 模块

urllib 模块是 Python 标准库,其价值在于抓取网络上的 URL 资源,入门爬虫时必学的一个模块。

不过更多的爬虫工程师上手学习的模块已经更换为 requests 了。

在 Python3 中 urllib 模块包括如下内容。

  • urllib.request:请求模块,用于打开和读取 URL;
  • urllib.error:异常处理模块,捕获 urllib.error 抛出异常;
  • urllib.parse:URL 解析,爬虫程序中用于处理 URL 地址;
  • urllib.robotparser:解析 robots.txt 文件,判断目标站点哪些内容可爬,哪些不可以爬,但是用的很少。

urllib.request.urlopen()函数

用于实现对目标url的访问。

from urllib.request import urlopen

with urlopen('https://www.example.net') as html:
    page = html.read()

print(page)

上述代码用到了 urllib.requests 模块,其内部定义了打开 URL 的函数,授权验证的方法,重定向,cookie 操作等方法。

代码中用到的 urlopen() 函数,就是打开一个 URL,该函数的语法格式如下所示:

urllib.request.urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
            *, cafile=None, capath=None, cadefault=False, context=None)

参数描述如下所示:

  • url:请求地址;
  • data:发送到服务器的其他数据对象,默认为 None;
  • timeout:超时时间;
  • cafile 和 capath:cafile 为 CA 证书, capath 为 CA 证书的路径,使用 HTTPS 需要用到;
  • context:ssl.SSLContext 类型,用来指定 SSL 设置。

调用该对象的 read() 方法,可以读取到整个网页数据。

其余的函数与文件读取类似,分别是 readline()readlines()

还可以调用对象的 getcode() 方法,获取网页状态码。

print(html.getcode()) # 返回 200

urlopen() 返回对象的更多方法

使用 urlopen() 可以得到一个 HTTPResposne 类型的对象,它包括上文提及的 read() 方法,getcode() 方法,除此之外,还有如下内容可以使用。

  • getheaders():获取请求头内容;
  • getheader(name):获取指定请求头;
  • msg:信息属性;
  • version:版本属性;
  • status:状态属性。

urllib.Request() 类

urllib .request

URL 请求抽象类,使用它可以扩展更多的请求配置,其构造方法如下所示:

def __init__(self, url, data=None, headers={},
                 origin_req_host=None, unverifiable=False,
                 method=None)

其参数说明如下所示:

  • url:请求地址,必选参数;
  • data:请求参数,必须为 bytes 类型数据,可以使用 urlencode() 进行编码;
  • headers:请求头设置,字典类型;
  • origin_req_host:请求的主机地址,IP 或域名;
  • method:请求方法。

测试代码如下所示:

from urllib import request, parse

url = 'http://httpbin.org/post'
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) 你的UA'
}
dict = {
    'name': 'xiangpica'
}
# 转换数据类型
data = bytes(parse.urlencode(dict), encoding='utf8')#将字典进行编码
# 实例化对象
req = request.Request(url=url, data=data, headers=headers, method='POST')
# 添加请求头
req.add_header('HOST', 'httpbin.org')
# 发送数据
response = request.urlopen(req)#实现对对象req的访问
print(response.read().decode('utf-8'))#将读取的网页数据按utf-8格式进行编码
  • urllib.parse.urlencode () 编码工作使用urllib.parse的 urlencode () 函数,帮我们将 key:value 这样的键值对转换成 "key=value" 这样的字符串,解码工作可以使用urllib.parse的 unquote () 函数。 

urllib.parse

该模块主要用于解析 URL,函数原型如下所示:

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)

参数说明如下:

  • urlstring:URL 地址;
  • scheme:协议类型,可用的包括 file、ftp、gopher、hdl、http、https、imap、mailto、 mms、news、nntp、prospero、rsync、rtsp、rtspu、sftp、 sip、sips、snews、svn、svn+ssh、telnet……;
  • allow_fragments:是否忽略 URL 中的 fragment 部分。

标准的 URL 格式如下:

scheme://netloc/path;params?query#fragment

说明如下所示

  • scheme:URL 协议;
  • netloc:域名和端口;
  • path:路径;
  • params:最后一个路径元素参数,不常用;
  • query:查询字符串;
  • fragment:片段标志。
from urllib.parse import urlparse

result = urlparse('http://www.example.com/index.html;info?id=10086#comment')
print(type(result), result)
print(result.scheme, result[0])
print(result.netloc, result[1])
print(result.path, result[2])
print(result.params, result[3])
print(result.query, result[4])
print(result.fragment, result[5])
  • urlparse() 返回结果是一个 ParseResult 类型的对象。

其余内容

  • urlunparse() 方法与上述方法逻辑相反;
  • urljoin() 方法用于拼接链接;
  • urlencode():格式化请求参数;
  • quote():将内容转换为 URL 编码格式,尤其是转换中文字符
  • unquote():对 URL 进行解码。

Python 正则表达式

正则表达式语法

正则表达式语法由字符和操作符构成,初期阶段掌握下述这些内容即可。

操作符 说明 例子
. 任何单个字符,极少不能匹配
[] 字符集,对单个字符给出取值范围 [abc] 表示匹配 a、b、c,[a-z] 表示 a 到 z 单个字符
[^] 非字符集,对单个字符给出排除范围 [^abc] 表示匹配 非 a、非 b、非 c 的单个字符
* 前一个字符 0 次或无限次扩展 abc* 表示 ab、abc、abcc、abccc 等
+ 前一个字符 1 次或无限次扩展 abc+ 表示 abc、abcc、abccc 等
? 前一个字符 0 次或 1 次 abc? 表示 ab、abc
| 左右表达式任意一个 abc|def 表示 abc 或者 def
{m} 扩展前 1 个字符 m 次 ab{2}c,表示 abbc
{m,n} 扩展前 1 个字符 m 到 n 次 ab{1,2}c,表示 abc、abbc
^ 匹配字符串开头 ^abc 表示 abc 在字符串开头
$ 匹配字符串结尾 abc$ 表示 abc 在字符串结尾
() 分组标记,内部仅能使用 | 操作符 (abc) 表示 abc,(a
\d 数字,等价于 [0-9]
\w 字符,等价于 [A-Za-z0-9]

以上表示仅仅为正则表达最基础部分内容,如果希望深入研究正则表达式,建议寻找更加全面的资料进行学习。

re 库基本用法

re 库主要函数如下:

  • 基础函数:compile
  • 功能函数:searchmatchfindallsplitfinditersub

原生字符串。

在 Python 中,表示原生字符串,需要在字符串前面加上 r
例如 my_str = 'i'am xiangpica' 在程序中会直接报错,
如果希望字符串中 ' 可以正常运行,需要加上转移字符 \,修改为 my_str = 'i\'am xiangpica'

  • 但这样结合上文正则表达式中的操作符,就会出现问题,因为 \ 在正则表达式中是有真实含义的,如果你使用 re 库去匹配字符串中的 \,那需要使用 4 个反斜杠,为了避免这种情况出现,引入了原生字符串概念。
# 不使用原生字符串的正则表达式  "\\\\"
# 使用原生字符串的正则表达式 r"\\"
  • 例子 
my_str='C:\number'

print(my_str)
C:
umber

本段代码的输出效果如下,\n 被解析成了换行,如果想要屏蔽这种现象,使用 r 即可:

my_str=r'C:\number'

print(my_str)

输出 C:\number

re.search 函数

该函数用于,在字符串中搜索正则表达式匹配到的第一个位置的值,返回 match 对象。
函数原型如下:

re.search(pattern,string,flags=0)

需求:在字符串 梦想橡皮擦 good good 中匹配 橡皮擦

import re
my_str='梦想橡皮擦 good good'
pattern = r'橡皮擦'

ret = re.search(pattern,my_str)
print(ret)

#输出匹配的结果
if ret:
    print(ret.group(0))
<re.Match object; span=(2, 5), match='橡皮擦'>
橡皮擦

search 函数的第三个参数 flags 表示正则表达式使用时的控制标记。

  • re.Ire.IGNORECASE:忽略正则表达式的大小写;
  • re.Mre.MULTILINE:正则表达式中的 ^ 操作符能够将给定字符串的每行当做匹配的开始;
  • re.Sre.DOTALL:正则表达式中的 . 操作符能够匹配所有字符。

re.match 函数

该函数用于将正则表达式与目标字符串的开始位置去匹配,返回 match 对象,未匹配成功返回 None,函数原型如下:

re.match(pattern,string,flags=0)

一定要注意是目标字符串开始位置。

import re
my_str = '梦想橡皮擦 good good'
pattern = r'梦' # 匹配到数据
pattern = r'good' # 匹配不到数据

ret = re.match(pattern, my_str)
if ret:
    print(ret.group(0))

re.match 和 re.search 方法都是一次最多返回一个匹配对象,如果希望返回多个值,
可以通过在 pattern 里加括号构造匹配组返回多个字符串。

re.findall 函数

该函数用于搜索字符串,以列表格式返回全部匹配到的字符串,函数原型如下:

re.findall(pattern,string,flags=0)

测试代码如下:

import re
my_str = '梦想橡皮擦 good good'
pattern = r'good'
ret = re.findall(pattern, my_str)
print(ret)

re.split 函数

该函数将一个字符串按照正则表达式匹配结果进行分割,返回一个列表。

re.split(pattern, string, maxsplit=0, flags=0)

re.split 函数进行分割的时候,如果正则表达式匹配到的字符恰好在字符串开头或者结尾,
返回分割后的字符串列表首尾都多了空格,需要手动去除,例如下述代码:

import re
my_str = '1梦想橡皮擦1good1good1'

pattern = r'\d'

ret = re.split(pattern, my_str)

print(ret)
#['', '梦想橡皮擦', 'good', 'good', '']

切换为中间的内容,则能正确的分割字符串。

import re
my_str = '1梦想橡皮擦1good1good1'

pattern = r'good'

ret = re.split(pattern, my_str)

print(ret)
#['1梦想橡皮擦1', '1', '1']

如果在 pattern 中捕获到括号,那括号中匹配到的结果也会在返回的列表中。

import re
my_str = '1梦想橡皮擦1good1good1'

pattern = r'(good)'

ret = re.split(pattern, my_str)

print(ret)
#['1梦想橡皮擦1', 'good', '1', 'good', '1']

maxsplit 参数表示最多进行分割次数, 剩下的字符全部返回到列表的最后一个元素,
例如设置匹配 1 次,得到的结果是 ['1梦想橡皮擦1', '1good1']

re.finditer 函数

搜索字符串,并返回一个匹配结果的迭代器,每个迭代元素都是 match 对象。
函数原型如下:

re.finditer(pattern,string,flags=0)

测试代码如下:

import re
my_str = '1梦想橡皮擦1good1good1'

pattern = r'good'

# ret = re.split(pattern, my_str,maxsplit=1)
ret =re.finditer(pattern, my_str)
print(ret)

re.sub 函数

在一个字符串中替换被正则表达式匹配到的字符串,返回替换后的字符串,
函数原型如下:

re.sub(pattern,repl,string,count=0,flags=0)

其中 repl 参数是替换匹配字符串的字符串,count 参数是匹配的最大替换次数。

import re
my_str = '1梦想橡皮擦1good1good1'

pattern = r'good'

ret = re.sub(pattern, "nice", my_str)
print(ret)

运行之后,得到替换之后的字符串:

1梦想橡皮擦1nice1nice1

re 库其它函数

其它比较常见的函数有:re.fullmatch()re.subn()re.escape()

Beautiful Soup

Beautiful Soup 是一款 Python 解析库,主要用于将 HTML 标签转换为 Python 对象树,然后让我们从对象树中提取数据。

模块的安装

pip install bs4 -i 国内任意源即可

该模块包名称为 bs4

import requests
from bs4 import BeautifulSoup


def ret_html():
    """获取HTML元素"""
    res = requests.get('https://www.crummy.com/software/BeautifulSoup/', timeout=3)
    return res.text


if __name__ == '__main__':
    html_str = ret_html()
    soup = BeautifulSoup(html_str, 'lxml')
    print(soup)

在 BeautifulSoup 类的构造函数中传递的两个参数,一个是待解析的字符串,另一个是解析器,官方建议的是 lxml,因其解析速度快。

import requests
from bs4 import BeautifulSoup


def ret_html():
    """获取HTML元素"""
    res = requests.get('https://www.crummy.com/software/BeautifulSoup/', timeout=3)
    return res.text


if __name__ == '__main__':
    html_str = ret_html()
    soup = BeautifulSoup(html_str, 'lxml')
    print(soup)
    

'''Site Search:

<form action="/search/" method="get">
<input maxlength="255" name="q" type="text" value=""/>
</form>
</td>
</tr>
</table>
</body>
</html>
'''

调用 soup 对象的 soup.prettify() 方法,可以将 HTML 标签进行格式化操作,这样你就可以在存储到外部文件的时候,让其 HTML 代码美观。

BeautifulSoup 模块的对象说明

BeautifulSoup 类可以将 HTML 文本解析成 Python 对象树,而这里面又包括最重要的四种对象,分别是 TagNavigableStringBeautifulSoupComment 对象。

BeautifulSoup 对象

代表整个 HTML 页面,而且实例化该对象的时候,还会自动补齐 HTML 代码。

    html_str = ret_html()
    soup = BeautifulSoup(html_str, 'lxml')
    print(type(soup))

Tag 对象

Tag 是标签,Tag 对象就是网页标签,或者叫做网页元素对象,例如获取 bs4 官网的 h1 标签对象:

if __name__ == '__main__':
    html_str = ret_html()
    soup = BeautifulSoup(html_str, 'lxml')
    # print(soup.prettify())  # 格式化 HTML

    print(soup.h1)

得到的也是网页中的 h1 标签:

<h1>Beautiful Soup</h1>

查看其类型:

    print(soup.h1)
    print(type(soup.h1))

得到的不是一个字符串,而是一个 Tag 对象。

<h1>Beautiful Soup</h1>
<class 'bs4.element.Tag'>

既然是 Tag 对象,那就会具备一些特定的属性值

  • 获取标签名称
    print(soup.h1)
    print(type(soup.h1))
    print(soup.h1.name)  # 获取标签名称h1
  • 通过 Tag 对象获取标签的属性值
    print(soup.img)  # 获取网页第一个 img 标签
    print(soup.img['src'])  # 获取网页元素DOM的属性值
    #DOM 是 web 页面的完全的面向对象表述
<img align="right" src="10.1.jpg" width="250"/>
10.1.jpg
  • 通过 attrs 属性获取标签的所有属性
    print(soup.img)  # 获取网页第一个 img 标签

    print(soup.img.attrs)  # 获取网页元素的所有属性值,以字典形式返回
{'align': 'right', 'src': '10.1.jpg', 'width': '250'}
<h1>Beautiful Soup</h1>
<class 'bs4.element.Tag'>
h1
<img align="right" src="10.1.jpg" width="250"/>
{'align': 'right', 'src': '10.1.jpg', 'width': '250'}

NavigableString 对象获取的是标签内部的文字内容,例如 p 标签,在下述代码中提取的是 我是橡皮擦

<p>我是橡皮擦</p>

获取该对象也非常容易,使用 Tag 对象的 string 属性即可。

    nav_obj = soup.h1.string
    print(type(nav_obj))

输出结果如下所示

<class 'bs4.element.NavigableString'>

如果目标标签是一个单标签,会获取到 None 数据

除了使用对象的 string 方法外,还可以使用 text 属性和 get_text() 方法来获取标签内容

    print(soup.h1.text)
    print(soup.p.get_text())
    print(soup.p.get_text('&'))

其中 text 是获取所有子标签内容的合并字符串,而 get_text() 也是相同的效果,不过使用 get_text() 可以增加一个分隔符,例如上述代码的 & 符号,还可以使用,strip=True 参数去除空格。

Comment 对象

获取网页注释内容,用处不大,忽略即可。

BeautifulSoup 对象和 Tag 对象支持标签查找方法,具体内容如下所示。

find() 方法和 find_all() 方法

调用 BeautifulSoup 对象和 Tag 对象的 find() 方法,可以在网页中找到指定对象,该方法的语法格式如下:

obj.find(name,attrs,recursive,text,**kws)

方法的返回结果是查找到的第一个元素,如果没查询到,返回 None。
参数说明如下:

  • name:标签名称;
  • attrs:标签属性;
  • recursive:默认搜索所有后代元素;
  • text:标签内容。

例如我们继续在上文请求的网页中,查找 a 标签,代码如下:

html_str = ret_html()
soup = BeautifulSoup(html_str, 'lxml')
print(soup.find('a'))

也可以使用 attrs 参数进行查找,代码如下:

html_str = ret_html()
soup = BeautifulSoup(html_str, 'lxml')
# print(soup.find('a'))
print(soup.find(attrs={'class': 'cta'}))

find() 方法还提供了一些特殊的参数,便于直接查找,例如可以使用 id=xxx,查找属性中包含 id 的标签,可以使用 class_=xxx,查找属性中包含 class 的标签。

print(soup.find(class_='cta'))

与 find() 方法成对出现的是 find_all() 方法,看名称就能知道其返回结果收是全部匹配标签,语法格式如下:

obj.find_all(name,attrs,recursive,text,limit)

其中重点说明一下 limit 参数,它表示最多返回的匹配数量,find() 方法可以看作 limit=1,这样就变得容易理解了。

猜你喜欢

转载自blog.csdn.net/m0_51933492/article/details/127773966