python 爬虫括号的用法

首先是文档说明:

>>> import re

>>> help(re.findall)

Help on function findall in module re:

findall(pattern, string, flags=0)

Return a list of all non-overlapping matches in the string.

If one or more capturing groups are present in the pattern, return

a list of groups; this will be a list of tuples if the pattern

has more than one group.

Empty matches are included in the result.

意思很明显,分组匹配下(一对括号内是一个组),findall函数返回元组形式的匹配结果,并且匹配为空也会返回到元组中。

所以一般用法是这样的:

>>> a = "one two three
four five six"

>>> import re

>>> b = re.findall(r"(one) (two) (three) (four) (five) (six)",a)#去掉了"|"号

>>> print(b)

[(‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘five‘, ‘six‘)]#按组将匹配结果添加到元组中返回

>>> b = re.findall(r"(one) (two) (three) (four)",a)

#不完全匹配

>>> print(b)

[(‘one‘, ‘two‘, ‘three‘, ‘four‘)]

#按组返回匹配成功部分,列表长度为1

>>> b = re.findall(r"one|two|three|four|five|six",a)

#不安组的条件匹配

>>> print(b)

[‘one‘, ‘two‘, ‘three‘, ‘four‘, ‘five‘, ‘six‘]#返回长度为6的列表

>>> b = re.findall(r"one two three four five six",a)

>>> print(b)

[‘one
two three four five six‘] #完全匹配,返回长度为1的列表

>>> b = re.findall(r"(one) (two) (three) (four) (five) (six)
(seven)",a)

>>> print(b)

[]#
没法全部匹配,返回空

>>> print (re.findall(r"[abc]","abc"))#[]的效果

[‘a‘,‘b‘,‘c‘]

>>> print (re.findall(r"a|b|c","abc"))#"|"的效果

[‘a‘,‘b‘,‘c‘]

通过以上实验可以得出的结论:

1条件匹配符"|"使得findall按每一种条件匹配一次,且"|"和"[]"效果是相同的,返回形式一样。

2圆括号分组匹配使得findall返回元组,元组中,几对圆括号就有几个元素,保留空匹配。

再看我提问中举的例子,将条件匹配与分组匹配结合在了一起。

>>> a = "one two three
four five six"

>>> b = re.findall("(one)|(two)|(three)|(four)|(five)|(six)",a)#加上了"|"号

>>> print(b)

[(‘one‘, ‘‘, ‘‘, ‘‘, ‘‘, ‘‘), (‘‘, ‘two‘, ‘‘, ‘‘, ‘‘, ‘‘),

(‘‘, ‘‘, ‘three‘, ‘‘, ‘‘, ‘‘),(‘‘, ‘‘, ‘‘, ‘four‘, ‘‘, ‘‘),

(‘‘, ‘‘, ‘‘, ‘‘, ‘five‘, ‘‘),(‘‘, ‘‘, ‘‘, ‘‘, ‘‘, ‘six‘)]

于是就理解了:

1这个结果是因为按组匹配所以有元组,每个元组都有六个元素。

2而因为是条件匹配,列了六种匹配条件,于是findall匹配六次,结果列表有六个元素。

3又因为每次匹配只能用一种条件,所以按组匹配结果列表中的每个元组只有一组有值而其他均为空。

这有什么用呢?比如:

>>> x = "3 min 46 sec
300 ms"

#分秒毫秒的提取

>>> print(re.findall(r"(\d{0,}) (min|sec|ms)",x))

[(‘3‘, ‘min‘), (‘46‘, ‘sec‘), (‘300‘, ‘ms‘)] #会不会很方便?

--------------------------------------------------------------------------------------------------

这个理解其实对下面那个问题(如何匹配某种单词搭配)没什么用,因为还有一个符号没有介绍,那就是"?:"符号,表示取消按分组返回。

#这个正则式子是随意写就的,

#按照人的思维理解。

#这个式子匹配以h或s为开头,ef或cd的(a或b)结尾为结尾的东西。

#一共有2*2*2八种可能性,findall的结果会有八个元素。

>>>
print(re.findall(r"\b((h|s)(ef|(cd|(a|b))))\b","sef scd sa sb
hef hcd ha hb"))

#不添加?:符号时结果如下:

#正则式子中的括号一共有五个,所以返回列表里的每个元组有五个元素

[(‘sef‘,
‘s‘, ‘ef‘, ‘‘, ‘‘), (‘scd‘, ‘s‘, ‘cd‘, ‘cd‘, ‘‘),

(‘sa‘, ‘s‘,
‘a‘, ‘a‘, ‘a‘), (‘sb‘, ‘s‘, ‘b‘, ‘b‘, ‘b‘),

(‘hef‘,
‘h‘, ‘ef‘, ‘‘, ‘‘), (‘hcd‘, ‘h‘, ‘cd‘, ‘cd‘, ‘‘),

(‘ha‘, ‘h‘,
‘a‘, ‘a‘, ‘a‘), (‘hb‘, ‘h‘, ‘b‘, ‘b‘, ‘b‘)]

#下面是加上"?:"的结果

>>>print(re.findall(r"\b(?:(?:h|s)(?:ef|(?:cd|(?:a|b))))\b","sef
scd sa sb hef hcd ha hb"))

[‘sef‘,
‘scd‘, ‘sa‘, ‘sb‘, ‘hef‘, ‘hcd‘, ‘ha‘, ‘hb‘]

#非常简洁

第一个式子返回的结果其实也算OK,因为已经覆盖到了所有的可能,只不过冗余项比较多,想得到纯粹的结果还要处理一次。

第二个式子加了"?:"后就简洁许多。

作为初学者,可能用不到分组这么复杂的正则式子,也就更不用提取消分组的符号了,所以很多正则的入门教程并不会花太多时间在这两项上。

所以现在就介绍一下如何解决匹配单词搭配的问题。

就比如说找数量结构的词组吧。

我们先进行书面的结构分析

数量结构是一种表示数量关系的短语,比如汉语中的一斤酒一两牛肉,由数词+量词+名词构成,也可以是一下,轻轻一按,用力一踢,由副词/+数词+动词构成。

在英语中数量结构又分为两种。

第一种是 a/an + n1 + of + n2,其中n1、n2是名词。比如 a piece of bread 。这种结构往往用来修饰不可数名词。

第二种是 num. + n 这个简单,就是数词+可数名词的复数形式,穷举所有的数词就行了。

第一种的正则式很简单,是这样的:

r"\ban{0,1}\b
\b\w+\b \bof\b \b\w+\b" #凡是在不定冠词和of之间的必然是名词,在of之外的是名词

第二种就稍微复杂一点,我们要把所有的数词都列出来,寻找其中的规律

差不多能分出这么几组

没有规律的:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve
twenty|forty)

结尾可加teen也可不加的:(?:(?:four)(?:teen){0,1})

结尾可加teen或ty也可不加的 :(?:(?:six|seven|eight|nine)|(?:ty|teen))

结尾必须加teen或ty的: (?:(?:fif|thir)(?:ty|teen))

把他们组合起来就是:

r"(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve
|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b"

再加上第一种可能就成了:

(?:\ban{0,1}\b
\b\w+\b
\bof\b)|(?:(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b)

这还只是选了前部分,后面还要接一个名词,所以:

(?:(?:\ban{0,1}\b \b\w+\b \bof\b)|(?:(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b)) (?:\b\w+\b)

于是这就是是完成状态了,我们来检测一下成果吧:

input

import rea = "a
cup of tea million stars forty people "

b = re.compile(r"(?:(?:\ban{0,1}\b
\b\w+\b
\bof\b)|(?:(?:(?:hundred|thounsand|million|billion|trillion|one|two|three|ten|five|eleven|twelve|twenty|forty)|(?:(?:four)(?:teen){0,1})|(?:(?:six|seven|eight|nine)|(?:ty|teen))|(?:(?:fif|thir)(?:ty|teen)))\b))
(?:\b\w+\b)")

print(re.findall(b,a))

output

[‘a
cup of tea‘, ‘million stars‘, ‘forty people‘]

这种眼花缭乱的式子,看着很麻烦,也不好解读,还好python提供了松散正则表达式。

只要在re.comile的第二个参数上填上"re.VERBOSE"即可写成如

‘‘‘

example

‘‘‘

注释的形式,此时空格不再被匹配,必须使用\s表达(下面这个版本已经更新了,这次更新囊括了所有的序数词):

a = "give me a kiss million stars one piece"

b = re.compile(r"""

#随时可以以#号备注

(?:\b\w+\b\s\b\w+\b\s)?

(?:

(?:\ban?\b\s\b\w+\b\s\bof\b)

|#第一类数量结构

(?:

(?:\b(?:one|two|three|five|first|second|third|fifth|sixth|an?))

|#fifth在这里 没有规律的数词 fifth sixth

(?:(?:hundred|thounsand|million|billion|trillion|ten|eleven|twel(?:f|ve))(?:th)?)

|

(?:(?:twent|fort)(?:y|ieth))

|

(?:(?:four)(?:teen|th)?)

|#加不加teen皆可的数词

(?:(?:six|seven|eight?|nine?)(?:(?:(?:t[yh])(?:eth)?)|(?:teen)(?:th)?)?)

|#加不加teen或ty皆可的数词

(?:(?:fif|thir)(?:(?:t[yi])(?:eth)?|(?:teen)(?:th)?))

#必须加teen或ty的数词 fifteen
thirteen fifty thirty  fiftieth thirtieth
fifteenth thirteenth

)\b#第二类数量结构

)\s

(?:\b\w+\b)#后跟的名词

""",re.VERBOSE)

这个式子到这里还是比较粗糙的,比如对于任何一文章中的“the one you”他都会当作数量结构匹配,所以还要增加一些其他条件来过滤这样的可能,不过我还没学到那个地步,所以我也没法解决这个问题,以后学会再来添加吧!

更新一下:

关键词:零宽断言

在python正则表达式中使用零宽断言,网上也有很多教程。

简单说,零宽断言要完成的目标是:当字符串符合一定条件,则匹配某些字符。

什么叫断言?

一个断言就是对条件做出判断,相当于if判断结构,满足条件,则做某事,不过else只能是不匹配。

什么叫零宽?

也就是这个东西所占的匹配字符中的宽度是零,也就是不匹配本身。

其他的关键词如零宽度正预测先行断言太复杂了我也不太清楚,就不讲了,会用就行。

使用方法:exp(?=exp)

在括号中使用?=后,这个括号内?=之后的字符就成了零宽断言所要判断的条件,前面括号之外的表达式则是判断满足条件要启用的匹配字符。

举例:

\w+(?=logy)

该表达式匹配任意以logy结尾的单词,但是不匹配logy本身。

如果要把这个判断放在前面,则要用:(?<=exp)exp

举例:

(?<=href=")http

可以匹配href="开头的http,但是不包括href=",这样的操作也省去了爬虫清洗数据时的一部分压力。

需要注意的是,前置的断言在python中不能使用不确定宽度的字符作为判断条件,必须确定字符的个数。所以如果你还想同时匹配(?<=src=")http,你不能写(?<=src="|href=")http,你可以写:

(?:(?<=src=")|(?<=href="))http

这是python实现的一个小缺陷。

不过后置的就可以这么写

http(?=src="|href=")

接着我们还有满足条件不匹配的用法,也就是在?后面加!。前置的就成了

(?!<=exp)

后置的成了(?!=exp)

这时候填写进去的字符,就成了遇到则不匹配的条件。

而我的数词查找就需要这个功能,来实现避免数词出现在省略先行词从句的开头的情况。

当然下面这个表达式是不能运行的,必须放到之前那个大串里。

re.compile(r"""

(?!

(?:

\b

(?:

(?:[Yy]ou|[Tt]hey)(?:‘re)?

|

I|to|with|in|[SsHh]h?e|[Ii]t

|

(?:[Tt]h)(?:is|at|e[sr]e|)

|

(?:(?:[Ww]h)(?:o[ms]?e?|ere|at|en|i[cl][he]))

)

\b

)

)

#筛掉的特殊词you I he she it this there that
those with to in which where what when while whose who whom

""",re.VERBOSE)

结合两者就是:

En_value =
re.compile(r"""

#随时可以以#号备注

#尾断言可以有不确定符号数的匹配,首断言不可以。

(?:\b\w+\b\s\b\w+\b\s)?

(?:

(?:\ban?\b\s\b\w+\b\s\bof\b)

|#第一类数量结构

(?:

(?:\b(?:one|two|three|five|first|second|third|fifth|sixth|an?))

|#fifth在这里 没有规律的数词 fifth sixth

(?:(?:hundred|thounsand|million|billion|trillion|ten|eleven|twel(?:f|ve))(?:th)?)

|

(?:(?:twent|fort)(?:y|ieth))

|

(?:(?:four)(?:teen|th)?)

|#加不加teen皆可的数词

(?:(?:six|seven|eight?|nine?)(?:(?:(?:t[yh])(?:eth)?)|(?:teen)(?:th)?)?)

|#加不加teen或ty皆可的数词

(?:(?:fif|thir)(?:(?:t[yi])(?:eth)?|(?:teen)(?:th)?))

#必须加teen或ty的数词 fifteen thirteen fifty thirty 
fiftieth thirtieth fifteenth thirteenth

)\b#第二类数量结构

)\s

(?!

(?:

\b

(?:

(?:[Yy]ou|[Tt]hey)(?:‘re)?

|

I|to|with|in|[SsHh]h?e|[Ii]t

|

(?:[Tt]h)(?:is|at|e[sr]e|)

|

(?:(?:[Ww]h)(?:o[ms]?e?|ere|at|en|i[cl][he]))

)

\b

)

)

#筛掉的特殊词(you I he she it this there
that those with to in which where what when while whose who whom

(?:\b\w+\b)#后跟的名词

""",re.VERBOSE)

时间: 2024-10-10 10:41:12

python 爬虫括号的用法的相关文章

Python爬虫-request的用法

import requests if __name__ == '__main__': #基本用法 #response = requests.get("http://httpbin.org/get") #print(response.text) #带参数的get #data = { # "name":"wu", # "age":21 #} #response = requests.get("http://httpbin

python爬虫的进阶用法

应用场景: 01: 去爬虫微信公众号文章,已知requests的执行方式实际就是执行里面request方法, 我们进行重写request方法的init,加入我们需要的字段: 如 callback --获取response执行回调函数     need_proxy --是否需要代理 fail_time --执行get获取url的失败次数   timeout = 10 from requests import Request TIMEOUT = 10 class WeixinRequest(Requ

Python爬虫利器四之PhantomJS的用法

前言 大家有没有发现之前我们写的爬虫都有一个共性,就是只能爬取单纯的html代码,如果页面是JS渲染的该怎么办呢?如果我们单纯去分析一个个后台的请求,手动去摸索JS渲染的到的一些结果,那简直没天理了.所以,我们需要有一些好用的工具来帮助我们像浏览器一样渲染JS处理的页面. 其中有一个比较常用的工具,那就是 PhantomJS Full web stack No browser required PhantomJS is a headless WebKit scriptable with a Ja

Python爬虫利器六之PyQuery的用法

前言 你是否觉得 XPath 的用法多少有点晦涩难记呢? 你是否觉得 BeautifulSoup 的语法多少有些悭吝难懂呢? 你是否甚至还在苦苦研究正则表达式却因为少些了一个点而抓狂呢? 你是否已经有了一些前端基础了解选择器却与另外一些奇怪的选择器语法混淆了呢? 嗯,那么,前端大大们的福音来了,PyQuery 来了,乍听名字,你一定联想到了 jQuery,如果你对 jQuery 熟悉,那么 PyQuery 来解析文档就是不二之选!包括我在内! PyQuery 是 Python 仿照 jQuery

Python爬虫进阶五之多线程的用法

前言 我们之前写的爬虫都是单个线程的?这怎么够?一旦一个地方卡到不动了,那不就永远等待下去了?为此我们可以使用多线程或者多进程来处理. 首先声明一点! 多线程和多进程是不一样的!一个是 thread 库,一个是 multiprocessing 库.而多线程 thread 在 Python 里面被称作鸡肋的存在!而没错!本节介绍的是就是这个库 thread. 不建议你用这个,不过还是介绍下了,如果想看可以看看下面,不想浪费时间直接看 multiprocessing 多进程 鸡肋点 名言: "Pyt

Python爬虫的Urllib库有哪些高级用法?

本文和大家分享的主要是python爬虫的Urllib库的高级用法相关内容,一起来看看吧,希望对大家学习python有所帮助. 1.分分钟扒一个网页下来 怎样扒网页呢?其实就是根据URL来获取它的网页信息,虽然我们在浏览器中看到的是一幅幅优美的画面,但是其实是由浏览器解释才呈现出来的,实质它 是一段HTML代码,加 JS.CSS,如果把网页比作一个人,那么HTML便是他的骨架,JS便是他的肌肉,CSS便是它的衣服.所以最重要的部分是存在于HTML中的,下面我 们就写个例子来扒一个网页下来. imp

Python爬虫利器:Selenium的用法

本文和大家分享的主要是python 爬虫 利器Selenium的相关内容,一起来看看吧,希望对大家 学习python爬虫有所帮助. Selenium  是什么?一句话,自动化测试工具.它支持各种浏览器,包括  Chrome , Safari , Firefox 等主流界面式浏览器,如果你在这些浏览器里面安装一个  Selenium  的插件,那么便可以方便地实现 Web界面的测试.换句话说叫  Selenium  支持这些浏览器驱动.话说回来, PhantomJS 不也是一个浏览器吗,那么  S

Python爬虫利器二之Beautiful Soup的用法

上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫Beautiful Soup,有了它我们可以很方便地提取出HTML或XML标签中的内容,实在是方便,这一节就让我们一起来感受一下Beautiful Soup的强大吧. 1. Beautiful Soup的简介 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据.官

Python爬虫入门之Urllib库的高级用法

1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览器,调试浏览器F12,我用的是Chrome,打开网络监听,示意如下,比如知乎,点登录之后,我们会发现登陆之后界面都变化了,出现一个新的界面,实质上这个页面包含了许许多多的内容,这些内容也不是一次性就加载完成的,实质上是执行了好多次请求,一般是首先请求HTML文件,然后加载JS,CSS 等等,经过多次