3. 正则表达式

正则表达

正则表达式的介绍

正则表达式是对字符串操作的一种逻辑公式,就是用实现定义好的一些特定的字符、及这些特定的字符的组合,组成 一个“规则字符串“,这个“规则字符串“用来表达对字符串的一种过滤逻辑。

注意: 正则表达式并不是Python独有的,Python中使用re模块实现。

常见匹配模式参考链接

元字符 描述
\w 匹配字母数字及下划线
\W 匹配非字母数字下划线
\s 匹配任意的空白符
\S 匹配任意非空白符
\d 匹配数字
\D 匹配任意非数字的字符
. 匹配除换行符以外的任意字符
^ 匹配字符串的开始
$ 匹配字符串的结束
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
a|b 匹配a或b
() 匹配括号内的表达式,也表示一个组

re.match()

尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配的话,match()就会返回None 语法: re.match(正则表达式,要匹配的字符串,匹配方式)

常用匹配方式

re.I 使匹配对大小写不敏感 re.S 使 . 匹配包括换行在内的所有字符

str1 = 'www.kaikeba.com' 
result = re.match('www',str1)

# 获取匹配的结果
print(result.group())

# 获取匹配字符串的长度范围
print(result.span())

# 不在起始位置匹配,返回None
print(re.match('kaikeba',str1))

# 默认大小写是敏感的
print(re.match('WWW',str1))

# 设置匹配模式,忽略大小写
print(re.match('WWW',str1,re.I))

多种匹配方式

str2 = 'abc 123 def'

# 常规匹配

print(re.match('^abc\s\d\d\d\sdef$',str2).group()) print(re.match('^abc\s\d{3}\sdef$',str2).group())

# 范匹配
print(re.match('^abc\s.*\sdef$',str2).group())

 
# 获取指定的字符
print(re.match('^abc\s(.*)\sdef$',str2).group(1))
# 通过re.group()获得结果后,如果正则表达式中有括号,则re.group(1)获取的就是第一个括号中匹配的结果

贪婪和非贪婪

# 贪婪匹配
content= "hello 1234567 World Demo"
result= re.match('^hello.*(\d+).*Demo',content) 
print(result)
print(result.group(1))
# 这种情况的原因是前面的.* 给匹配掉了, .*在这里会尽可能的匹配多的内容,也就是我们所说的贪婪匹配
result= re.match('^hello.*?(\d+).*Demo',content)
print(result) 
print(result.group(1))

匹配模式

# 很多时候匹配的内容是存在换行的问题的,这个时候的就需要用到匹配模式re.S来匹配换行的内容

content = """hello 123456 world demo"""

result =re.match('^he.*?(\d+).*?demo$',content,re.S) 
print(result)
print(result.group()) 
print(result.group(1))

转义

# 当我们要匹配的内容中存在特殊字符的时候,就需要用到转移符号\ 
content= "price is $5.00"
result = re.match('price is \$5\.00',content) 
print(result)
print(result.group())

re.search()

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

import re

html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齐秦">往事随风</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

result = re.search('<li.*?active.*?singer="(.*?)">(.*?)</a>',html,re.S) 
print(result)
print(result.groups()) 
print(result.group(1)) 
print(result.group(2))

# 所以为了匹配方便,我们会更多的用search,不用match,match必须匹配头部,所以很多时候不是特别方便

re.findall()

搜索字符串,以列表的形式返回全部能匹配的子串

import re
html =  '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齐秦">往事随风</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

 

results = re.findall('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>', html, re.S) 
print(results)
print(type(results)) 
for result in results:
    print(result)
    print(result[0], result[1], result[2])

re.compile()

将正则字符串编译成正则表达式对象,以便于复用该匹配模式。

import re
html = '''<div id="songs-list">
    <h2 class="title">经典老歌</h2>
    <p class="introduction">
        经典老歌列表
    </p>
    <ul id="list" class="list-group">
        <li data-view="2">一路上有你</li>
        <li data-view="7">
            <a href="/2.mp3" singer="任贤齐">沧海一声笑</a>
        </li>
        <li data-view="4" class="active">
            <a href="/3.mp3" singer="齐秦">往事随风</a>
        </li>
        <li data-view="6"><a href="/4.mp3" singer="beyond">光辉岁月</a></li>
        <li data-view="5"><a href="/5.mp3" singer="陈慧琳">记事本</a></li>
        <li data-view="5">
            <a href="/6.mp3" singer="邓丽君">但愿人长久</a>
        </li>
    </ul>
</div>'''

pattern = re.compile('<li.*?href="(.*?)".*?singer="(.*?)">(.*?)</a>',re.S) 
results = re.findall(pattern, html)
print(results) 
print(type(results)) 
for result in results:
    print(result)
    print(result[0], result[1], result[2])

拓展(re.sub)

替换字符串中每一个匹配的子串后返回替换后的字符串

语法:re.sub(正则表达式,替换成的字符串,原字符串)

import re
content = "hello 123456 World"
# content = re.sub('\d+','',content) # print(content)
#有些情况下我们替换字符的时候,还想获取我们匹配的字符串,然后在后面添加一些内容
#需要注意的一个问题是\1是获取第一个匹配的结果,为了防止转义字符的问题,我们需要在前面加上r
content = re.sub('(\d+)',r'\1 7890',content) 
print(content)
2020/02/21 posted in  爬虫

4. python解析库的使用

BeautifulSoup库的基本使用

简介

正则表达式对于我们来说用起来是不方便的,而且需要记很多规则,所以用起来不是特别熟练。  BeautifulSoup库一个灵活又方便的网页解析库,处理高效,支持多种解析器。  利用它就不用编写正则表达式也能方便的实现网页信息的抓取。

中文参考文档

安装

image.png

基础使用

from bs4 import BeautifulSoup 
html = '''
    <body>
    <header id="header">
        <h3 id="name">小强也可爱</h3>
        <title>标题</title>
    <div class="sns">
        <a href="http://www.kaikeba.com/feed/" target="_blank" rel="nofollow" title="RSS"><i class="fa fa-rss" aria-hidden="true"></i></a>
            <a href="http://kaikeba.com/kaikeba" target="_blank" rel="nofollow" title="Weibo"><i class="fa fa-weibo" aria-hidden="true"></i></a>
                <a href="https://www.kaikeba.com/in/kaikeba" target="_blank" rel="nofollow" title="Linkedin"><i class="fa fa-linkedin" aria-hidden="true"></i></a>
                <a href="mailto:kaikeba@gmail.com" target="_blank" rel="nofollow" title="envelope"><i class="fa fa-envelope" aria-hidden="true"></i></i></a>
            </div>
    <div class="nav">
        <ul><li class="current-menu-item"><a [href="http://www.kaikeb](http://www.kaikeba.com/)a.com/">hello</a></li>
    <li><a [href="http://www.kaikeba.com/about-me/">word](http://www.kaikeba.com/about-me/)
    <li><a [href="http://www.kaikeba.com/post-search/">nihao>
    <li><a [href="http://www.kaikeba.com/wp-login.php">kkb](http://www.kaikeba.com/wp-login.php)
    </ul> </div>
    </header>
    </body> '''

soup = BeautifulSoup(html,'lxml')

# 格式化输出 soup 对象的内容
print(soup.prettify())

# 根据标签名获取整个标签(但是拿出的是第一个) print(soup.li)
# 获取标签的名字
print(soup.title.name)

# 获取标签中的文本
print(soup.title.string)

# 获取标签title的父标标签
print(soup.title.parent.name)

 

# 获取li标签的子标签
print(soup.li.contents)

 

# 获取便签的属性值的两种方式
print(soup.li["class"]) print(soup.li.attrs['class'])

# 使用select,css选择器
print(soup.select('li'))

# 类 名 前 加 .,id 名 前 加 # 
print(soup.select('.current-menu-item'))

# 获取内容
print(soup.select('.current-menu-item')[0].get_text())

# 获取属性值
print(soup.select('.current-menu-item')[0].attrs['class'])


# 获取li标签下面的子标签
print(soup.select('li > a')[1].get_text())

# 使用find和findall进行查找
print(soup.find('li',attrs={'class':'current-menu-item'}))
print(soup.find_all('li',attrs={"class":"current-menu-item"})[0])

Xpath的基本使用

简介

XPath 是一门在 XML 文档中查找信息的语言。 使用路径表达式来选取 XML 文档中的节点或者节点集。注意: xpath速度比较快,是爬虫在网页定位中的较优选择,但是很多网页前端代码混乱难以定位。

安装:pip install lxml

语法

xpath的更多语法

表达式 描述
nodename 选取此节点的所有子节点。
/ 从根节点选取。
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。

基础使用

# 导入lxml的etree库
from lxml import etree


data_str = """
    <div>
        <ul>
            <li class="item-0"><a href="link1.html">first item</a></li>
            <li class="item-1"><a href="link2.html">second item</a></li>
            <li class="item-inactive"><a href="link3.html">third item</a></li>
            <li class="item-1"><a href="link4.html">fourth item</a></li>
            <li class="item-0"><a href="link5.html">fifth item</a>
        </ul>
    </div> 
    """
# 注意: 该数据中缺少了一个li标签的闭合标签
# 利用etree.HTML可以将字符串或者bytes转化为Element python对象,这个对象具有Xpath的方法
html = etree.HTML(data_str)
# print(html)

# etree.tostring(html)可以自动修正HTML代码,补全了缺胳膊少腿的标签
# 使用为了观察修改以后的html样子,根据修改后的HTML去写Xpath
result = etree.tostring(html) 
print(result.decode("utf-8"))


# 获取class =item-1 的 a标签的href属性
result = html.xpath('//li[@class="item-1"]/a/@href') 
print(result)

# 获取class =item-1 的 a标签的文本值
result = html.xpath('//li[@class="item-1"]/a/text()') 
print(result)

PyQuery的使用

简介

pyquery库是jQuery的Python实现,能够以jQuery的语法来操作解析 HTML 文档, 易用性和解析速度都很好,和它差不多的还有BeautifulSoup,都是用来解析的。

官方文档

安装

终端执行: pip install pyquery

文件中测试: import pyquery

初始化pyquery对象

#将字符串初始化

html = """
<html lang="en">
    <head>
        <title>PyQuery</title>
    </head>
    <body>
        <ul id="container">
            <li class="o1">MM</li>
            <li class="o2">MN</li>
            <li class="o3">GN</li>
        </ul>
    </body>
</html> """

from pyquery import PyQuery as pq

#初始化为PyQuery对象
doc = pq(html)

print(type(doc)) 
print(doc)

# 将HTML文件初始化
doc = pq(filename = './pyquery_demo.html') 
print(type(doc))
print(doc)

 

#  对网址响应进行初始化

doc = pq(url='http://www.baidu.com') 
print(type(doc))
print(doc)

常用css选择器获取标签

html = """
<html lang="en">
    <head>
        <title>PyQuery</title>
    </head>
    <body>
        <ul id="container">
            <li class="o1">MM</li>
            <li class="o2 active">MN<a class='o22'>fad</a></li>
            <li class="o3">GN</li>
        </ul>
    </body>
</html> 
"""

from pyquery import PyQuery as pq
#用css选择器来实现,如果要选id前面加#,如果选class,前面加.,如果选标签名,什么也不加
doc = pq(html)
# 根据标签
# print(doc('title'))
# print(doc('#container')) 
#print(doc('.o1'))
# 组合标签
print(doc('.o2.active'))#空格表示里面,没有空格表示整体
print(doc('.o2 .o22'))#空格表示里面,没有空格表示整体

# 伪类选择器
# print(doc('li:nth-child(2)'))

# 根据标签内容获取标签
# print(doc("li:contains('MM')"))

#利用find方法
# print(doc.find('li'))

# 也可以用.children()查找直接子元素
# container = doc.find('#container') 
# print(container.children())

#.parent()查找对象的父元素
# object_2 = doc.find('.o2') 
# print(object_2.parent())

#.parents()祖先节点
# object_2 = doc.find('.o2')
# parent = object_2.parents('#container')#当然也可以传入参数# print(parent)

#.siblings()兄弟元素,即同级别的元素,不包括自己 
# object_2 = doc.find('.o2')
# print(object_2.siblings())

 

# 遍 历
# doc = pq(html)
# lis = doc('li').items()#.items会是一个生成器
# print(type(lis))
# for li in lis: #   print(li)

# 5.filter() ——根据类名、id名得到指定元素,例:
# d=pq("<div><p id='1'>test 1</p><p class='2'>test 2</p></div>") 
# d('p').filter('#1') #返回[<p#1>]
# d('p').filter('.2') #返回[<p.2>]

# 6.eq(index) ——根据给定的索引号得到指定元素
# 接上例,若想得到第二个p标签内的内容,则可以:
# print d('p').eq(1).html() #返回test 2

获取标签信息

html = """
<html lang="en">
    <head>
        <title>PyQuery</title>
    </head>
    <body>
        <ul id="container">
            <li class="o1">MM</li>
            <li class="o2 active">MN<a class='o22'>fad</a></li>
            <li class="o3">GN</li>
        </ul>
    </body>
</html> 
"""
from pyquery import PyQuery as pq 
doc = pq(html)

# 获取属性值
# o2 = doc.find('.o2')
# print(o2.attr('class'))

#  获取文本值
o2 = doc.find('.o2')
print(o2.text())
2020/02/21 posted in  爬虫