c 抓取网页数据(Python爬虫世界里必不可少的神兵利器-页面解析和数据提取)

优采云 发布时间: 2022-03-30 15:14

  c 抓取网页数据(Python爬虫世界里必不可少的神兵利器-页面解析和数据提取)

  页面解析和数据提取javascript

  一般来说,对于我们来说,需要爬取的是一个网站或者一个应用的内容,以提取有用的价值。内容通常分为两部分,非结构化数据和结构化数据。php

  非结构化数据处理文本、电话号码、电子邮件地址HTML 文档结构化数据处理JSON 文档XML 文档为什么要学习正则表达式

  其实爬虫主要有四个步骤: css

  清除目标(知道要在哪个范围内搜索或网站) 爬取(爬取网站的所有内容) 获取(删除对我们无用的数据) 处理数据(根据以我们想要的方式存储和使用)

  我们实际上省略了步骤 3,即昨天案例中的“采取”步骤。由于我们下载的数据都是网页,数据庞大而混乱,而且大部分是我们不关心的,所以我们需要根据自己的需要进行过滤和匹配。html

  所以对于文本过滤或者规则匹配来说,最厉害的就是正则表达式,它是Python爬虫世界里不可或缺的利器。爪哇

  什么是正则表达式

  正则表达式也称为正则表达式,一般用于检索和替换符合某种模式(规则)的文本。节点

  正则表达式是一个字符串操作的逻辑公式,就是用一些预先定义好的特定字符和这些特定字符的组合组成一个“规则字符串”,而这个“规则字符串”用来表达A过滤逻辑字符串。Python

  给定一个正则表达式和另一个字符串,我们可以实现以下目标: 程序员

  

  正则表达式匹配规则

  

  Python的re模块

  在 Python 中,我们可以通过内置的 re 模块来使用正则表达式。网络

  需要注意的一点是正则表达式使用特殊字符的转义,所以如果我们想使用原创字符串,只需添加一个 r 前缀,例如:正则表达式

  r'chuanzhiboke\t\.\tpython'

  使用 re 模块的通常步骤如下:

  使用compile()函数将正则表达式的字符串形式编译成Pattern对象

  通过Pattern对象提供的一系列方法,对文本进行匹配查找,得到匹配结果,就是一个Match对象。

  最后,使用 Match 对象提供的属性和方法来获取信息,并根据需要执行其余操作。编译函数

  compile函数用于编译正则表达式并生成Pattern对象,通常以如下形式使用:

  import re

# 将正则表达式编译成 Pattern 对象

pattern = re.compile(r'\d+')

  上面,我们已经将一个正则表达式编译成一个 Pattern 对象。接下来,我们可以使用pattern的一系列方法来匹配文本。

  Pattern 对象的一些常用方法是:

  匹配方法

  match方法用于查找字符串的头部(也可以指定起始位置),是一个匹配,只要找到一个匹配的结果,就会返回,而不是查找所有的匹配结果。它通常以下列形式使用:

  match(string[, pos[, endpos]])

  其中,string为要匹配的字符串,pos和endpos为可选参数,指定字符串的起止位置,默认值分别为0和len(字符串长度)。所以,当你不指定 pos 和 endpos 时,match 方法默认匹配字符串的头部。

  当匹配成功时,返回一个 Match 对象,如果没有匹配,则返回 None。

  >>> import re

>>> pattern = re.compile(r'\d+') # 用于匹配至少一个数字

  >>> m = pattern.match('one12twothree34four') # 查找头部,没有匹配

>>> print m

  None

  >>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配

>>> print m

  None

  >>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配

>>> print m # 返回一个 Match 对象

  >>> m.group(0) # 可省略 0

  '12'

  >>> m.start(0) # 可省略 0

  3

  >>> m.end(0) # 可省略 0

  5

  >>> m.span(0) # 可省略 0

  (3, 5)

  上面,匹配成功时返回一个 Match 对象,其中:

  让我们看另一个例子:

  >>> import re

>>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I) # re.I 表示忽略大小写

>>> m = pattern.match('Hello World Wide Web')

>>> print m # 匹配成功,返回一个 Match 对象

  >>> m.group(0) # 返回匹配成功的整个子串

  'Hello World'

  >>> m.span(0) # 返回匹配成功的整个子串的索引

  (0, 11)

  >>> m.group(1) # 返回第一个分组匹配成功的子串

  'Hello'

  >>> m.span(1) # 返回第一个分组匹配成功的子串的索引

  (0, 5)

  >>> m.group(2) # 返回第二个分组匹配成功的子串

  'World'

  >>> m.span(2) # 返回第二个分组匹配成功的子串

  (6, 11)

  >>> m.groups() # 等价于 (m.group(1), m.group(2), ...)

  ('Hello', 'World')

  >>> m.group(3) # 不存在第三个分组

  Traceback (most recent call last): File "", line 1, in IndexError: no such group

  -------------------------------------------------- -------------------------------------------------- -- 搜索方法

  search 方法用于查找字符串中的任何位置。这也是一场比赛。只要找到匹配结果,就会返回,而不是查找所有匹配结果。它通常以下列形式使用:

  搜索(字符串[,pos[,endpos]])

  其中,string为要匹配的字符串,pos和endpos为可选参数,指定字符串的起止位置,默认值分别为0和len(字符串长度)。

  当匹配成功时,返回一个 Match 对象,如果没有匹配,则返回 None。

  让我们看一个例子:

  >>> import re

>>> pattern = re.compile('\d+')

>>> m = pattern.search('one12twothree34four') # 这里若是使用 match 方法则不匹配

>>> m

>>> m.group()

'12'

>>> m = pattern.search('one12twothree34four', 10, 30) # 指定字符串区间

>>> m

>>> m.group()

'34'

>>> m.span()

(13, 15) 

  让我们看另一个例子:

  # -*- coding: utf-8 -*-

import re

# 将正则表达式编译成 Pattern 对象

pattern = re.compile(r'\d+')

# 使用 search() 查找匹配的子串,不存在匹配的子串时将返回 None

# 这里使用 match() 没法成功匹配

m = pattern.search('hello 123456 789')

if m:

# 使用 Match 得到分组信息

print 'matching string:',m.group()

# 起始位置和结束位置

print 'position:',m.span()

  结果:

  matching string: 123456

position: (6, 12)

  -------------------------------------------------- -------------------------------------------------- -- findall 方法

  以上匹配和搜索方式都是一次性匹配,只要找到匹配结果,就会返回。但是,大多数时候,我们需要搜索整个字符串来获得所有匹配的结果。

  findall 方法可以按以下形式使用:

  findall(string[, pos[, endpos]])

  其中,string为要匹配的字符串,pos和endpos为可选参数,指定字符串的起止位置,默认值分别为0和len(字符串长度)。

  findall 将所有匹配的子字符串作为一个列表返回,如果没有匹配则返回一个空列表。

  看一下这个例子:

  import re

pattern = re.compile(r'\d+') # 查找数字

result1 = pattern.findall('hello 123456 789')

result2 = pattern.findall('one1two2three3four4', 0, 10)

print result1

print result2

  结果:

  ['123456', '789']

['1', '2']

  我们先来看一个栗子:

  # re_test.py

import re

#re模块提供一个方法叫compile模块,提供咱们输入一个匹配的规则

#而后返回一个pattern实例,咱们根据这个规则去匹配字符串

pattern = re.compile(r'\d+\.\d*')

#经过partten.findall()方法就可以所有匹配到咱们获得的字符串

result = pattern.findall("123.141593, 'bigcat', 232312, 3.15")

#findall 以 列表形式 返回所有能匹配的子串给result

for item in result:

print item

  运行结果:

  123.141593

3.15

  -------------------------------------------------- -------------------------------------------------- -- 查找器方法

  finditer 方法的行为类似于 findall 的行为,同样会搜索整个字符串并获取所有匹配的结果。但它返回一个迭代器,该迭代器按顺序访问每个匹配结果(Match 对象)。

  看一下这个例子:

  # -*- coding: utf-8 -*-

import re

pattern = re.compile(r'\d+')

result_iter1 = pattern.finditer('hello 123456 789')

result_iter2 = pattern.finditer('one1two2three3four4', 0, 10)

print type(result_iter1)

print type(result_iter2)

print 'result1...'

for m1 in result_iter1: # m1 是 Match 对象

print 'matching string: {}, position: {}'.format(m1.group(), m1.span())

print 'result2...'

for m2 in result_iter2:

print 'matching string: {}, position: {}'.format(m2.group(), m2.span())

  结果:

  

result1...

matching string: 123456, position: (6, 12)

matching string: 789, position: (13, 16)

result2...

matching string: 1, position: (3, 4)

matching string: 2, position: (7, 8)

  -------------------------------------------------- -------------------------------------------------- -- 分割方法

  split 方法根据可以匹配的子字符串将字符串拆分后返回一个列表。它可以以下列形式使用:

  split(string[, maxsplit]) 

  其中,maxsplit 用于指定最大拆分次数,而不是指定所有拆分。

  看一下这个例子:

  import re

p = re.compile(r'[\s\,\;]+')

print p.split('a,b;; c d')

  结果:

  ['a', 'b', 'c', 'd']

  -------------------------------------------------- -------------------------------------------------- -- 子方法

  sub 方法用于替换。它以下列形式使用:

  sub(repl, string[, count])

  其中,repl 可以是字符串,也可以是函数:

  看一下这个例子:

  import re

p = re.compile(r'(\w+) (\w+)') # \w = [A-Za-z0-9]

s = 'hello 123, hello 456'

print p.sub(r'hello world', s) # 使用 'hello world' 替换 'hello 123' 和 'hello 456'

print p.sub(r'\2 \1', s) # 引用分组

def func(m):

return 'hi' + ' ' + m.group(2)

print p.sub(func, s)

print p.sub(func, s, 1) # 最多替换一次 

  结果:

  hello world, hello world

123 hello, 456 hello

hi 123, hi 456

hi 123, hello 456

  -------------------------------------------------- -------------------------------------------------- -- 匹配中文

  在某些情况下,我们希望匹配文本中的汉字。需要注意的一点是,中文的unicode编码范围主要在[u4e00-u9fa5],这主要是因为这个范围不完整,比如不包括全角(中文)标点,但是,在大多数情况下。

  假设现在要提取字符串title = u'hello, hello, world'中的中文,可以这样:

  import re

title = u'你好,hello,世界'

pattern = re.compile(ur'[\u4e00-\u9fa5]+')

result = pattern.findall(title)

print result

  请注意,我们为正则表达式添加了两个前缀 ur,其中 r 表示使用原创字符串,u 表示它是 unicode 字符串。

  结果:

  [u'\u4f60\u597d', u'\u4e16\u754c']

  注意:贪心模式和非贪心模式贪心模式:在整个表达式匹配成功的前提下,尽量匹配(*);非贪心模式:在整个表达式匹配成功的前提下,尽量少匹配(?);Python 中的量词默认是贪婪的。示例 1:源字符串:abbbc 示例 2:源字符串:aa

  测试1

  bb

  测试2

  抄送

  这是贪婪模式。匹配到第一个“

  ",整个表达式都可以匹配成功,但是因为使用了贪心模式,所以还是要尝试向右匹配,看是否有更长的子串可以匹配成功。匹配到第二个"

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线