51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 1299|回复: 2
打印 上一主题 下一主题

python3爬虫之入门和正则表达式

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2018-4-23 14:14:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前面的python3入门系列基本上也对python入了门,从这章起就开始介绍下python的爬虫教程,拿出来给大
家分享;爬虫说的简单,就是去抓取网路的数据进行分析处理;这章主要入门,了解几个爬虫的小测试,以
及对爬虫用到的工具介绍,比如集合,队列,正则表达式;
用python抓取指定页面:

代码如下:

  1. import urllib.request

  2. url= "http://www.baidu.com"
  3. data = urllib.request.urlopen(url).read()#
  4. data = data.decode('UTF-8')
  5. print(data)
  6. urllib.request.urlopen(url)
复制代码

官方文档返回一个 http.client.HTTPResponse 对象, 这个对象又用到的read()方法;返
回数据;这个函数返回一个 http.client.HTTPResponse 对象, 这个对象又有各种方法, 比如我们用到的read()方法;

查找可变网址:

  1. import urllib
  2. import urllib.request
  3. data={}
  4. data['word']='one peace'
  5. url_values=urllib.parse.urlencode(data)
  6. url="http://www.baidu.com/s?"
  7. full_url=url+url_values
  8. a = urllib.request.urlopen(full_url)
  9. data=a.read()
  10. data=data.decode('UTF-8')
  11. print(data)
  12. ##打印出网址:
  13. a.geturl()
复制代码

data是一个字典, 然后通过urllib.parse.urlencode()来将data转换为 ‘word=one+peace’的字符串, 最后和url合并为full_url

python正则表达式介绍:

队列 介绍

在爬虫的程序中用到了广度优先级算法,该算法用到了数据结构,当然你用list也可以实现队列,但是效率不高。
现在在此处介绍下:
在容器中有队列:collection.deque

#队列简单测试:
from collections import deque
queue=deque(["peace","rong","sisi"])
queue.append("nick")
queue.append("pishi")
print(queue.popleft())
print(queue.popleft())
print(queue)
集合介绍:

在爬虫程序中, 为了不重复爬那些已经爬过的网站, 我们需要把爬过的页面的url放进集合中, 在每一次要爬某一
个url之前, 先看看集合里面是否已经存在. 如果已经存在, 我们就跳过这个url; 如果不存在, 我们先把url放入集合
中, 然后再去爬这个页面.
Python 还 包 含 了 一 个 数 据 类 型—— set ( 集 合 ) 。 集 合 是 一 个 无 序 不 重 复 元素 的 集 。 基 本 功
能 包 括 关 系 测 试 和 消 除 重 复 元 素 。 集 合 对 象 还 支 持 union( 联
合),intersection(交),difference(差)和 sysmmetric difference(对称差集)等数学运算。
大括号或 set() 函数可以用来创建集合。 注意:想要创建空集合,你必须使用set() 而不是 {} 。{}用于创建空字典;

集合的创建演示如下:

  1. a={"peace","peace","rong","rong","nick"}
  2.    print(a)
  3.    "peace" in  a
  4.    b=set(["peace","peace","rong","rong"])
  5.    print(b)
  6.    #演示联合
  7.    print(a|b)
  8.    #演示交
  9.    print(a&b)
  10.    #演示差
  11.    print(a-b)
  12.   #对称差集
  13.   print(a^b)
  14. #输出:   
  15. {'peace', 'rong', 'nick'}
  16. {'peace', 'rong'}
  17. {'peace', 'rong', 'nick'}
  18. {'peace', 'rong'}
  19. {'nick'}
  20. {'nick'}
复制代码

正则表达式

在爬虫时收集回来的一般是字符流,我们要从中挑选出url就要求有简单的字符串处理能力,而用正则表达式可以
轻松的完成这一任务;
正则表达式的步骤:1,正则表达式的编译 2,正则表达式匹配字符串 3,结果的处理
下图列出了正则表达式的语法:

在pytho中使用正则表达式,需要引入re模块;下面介绍下该模块中的一些方法;

1.compile和match

re模块中compile用于生成pattern的对象,再通过调用pattern实例的match方法处理文本最终获得match实例;
通过使用match获得信息;

import re

# 将正则表达式编译成Pattern对象
pattern = re.compile(r'rlovep')
# 使用Pattern匹配文本,获得匹配结果,无法匹配时将返回None
m = pattern.match('rlovep.com')
if m:
# 使用Match获得分组信息
    print(m.group())
### 输出 ###
# rlovep
re.compile(strPattern[, flag]):
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为Pattern对象。 第二个参数flag是
匹配模式,取值可以使用按位或运算符'|'表示同时生效,比如re.I | re.M。另外,你也可以在regex字符串中
指定模式,比如re.compile('pattern', re.I | re.M)与re.compile('(?im)pattern')是等价的。
可选值有:

re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)

M(MULTILINE): 多行模式,改变'^'和'$'的行为(参见上图)
S(DOTALL): 点任意匹配模式,改变'.'的行为
L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。

Match:
Match对象是一次匹配的结果,包含了很多关于此次匹配的信息,可以使用Match提供的可读属性或方法来获
取这些信息。


属性:

string: 匹配时使用的文本。
re: 匹配时使用的Pattern对象。
pos: 文本中正则表达式开始搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
endpos: 文本中正则表达式结束搜索的索引。值与Pattern.match()和Pattern.seach()方法的同名参数相同。
lastindex: 最后一个被捕获的分组在文本中的索引。如果没有被捕获的分组,将为None。
lastgroup: 最后一个被捕获的分组的别名。如果这个分组没有别名或者没有被捕获的分组,将为None。
方法:

group([group1, …]):
获得一个或多个分组截获的字符串;指定多个参数时将以元组形式返回。group1可以使用编号也可以使用
别名;编号0代表整个匹配的子串;不填写参数时,返回group(0);没有截获字符串的组返回None;截获
了多次的组返回最后一次截获的子串。
groups([default]):
以元组形式返回全部分组截获的字符串。相当于调用group(1,2,…last)。default表示没有截获字符串的组以
这个值替代,默认为None。
groupdict([default]):
返回以有别名的组的别名为键、以该组截获的子串为值的字典,没有别名的组不包含在内。default含义同上。
start([group]):
返回指定的组截获的子串在string中的起始索引(子串第一个字符的索引)。group默认值为0。
end([group]):
返回指定的组截获的子串在string中的结束索引(子串最后一个字符的索引+1)。group默认值为0。
span([group]):
返回(start(group), end(group))。
expand(template):
将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、 \g<name>引用分组,但不能
使用编号0。\id与\g<id>是等价的;但\10将被认为是第10个分组,如果你想表达 \1之后是字符'0',只能使
用\g<1>0。
pattern:
Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。

Pattern不能直接实例化,必须使用re.compile()进行构造。


Pattern提供了几个可读属性用于获取表达式的相关信息:

pattern: 编译时用的表达式字符串。
flags: 编译时用的匹配模式。数字形式。
groups: 表达式中分组的数量。
groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
实例方法[ | re模块方法]:

match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]):
这个方法将从string的pos下标处起尝试匹配pattern;如果pattern结束时仍可匹配,则返回一个Match对象;如
果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。
pos和endpos的默认值分别为0和len(string);re.match()无法指定这两个参数,参数flags用于编译pattern时指
定匹配模式。
注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可
以在表达式末尾加上边界匹配符'$'。
search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]):
这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,如果pattern结束时
仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1重新尝试匹配;直到pos=endpos时仍无法匹配则
返回None。 pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译
pattern时指定匹配模式。
split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]):
按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。
findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]):
搜索string,以列表形式返回全部能匹配的子串。
finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。
sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):
使用repl替换string中每一个匹配的子串后返回替换后的字符串。 当repl是一个字符串时,可以使用\id或\g<id>、
\g<name>引用分组,但不能使用编号0。 当repl是一个方法时,这个方法应当只接受一个参数(Match对象),
并返回一个字符串用于替换(返回的字符串中不能再引用分组)。 count用于指定最多替换次数,不指定时全部
替换。
subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]):
返回 (sub(repl, string[, count]), 替换次数)。
2.re.match(pattern, string, flags=0)

函数参数说明:



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

x
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏
回复

使用道具 举报

该用户从未签到

2#
 楼主| 发表于 2018-4-23 14:14:45 | 只看该作者
参数        描述
pattern        匹配的正则表达式
string        要匹配的字符串。
flags        标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.match方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法        描述
group(num=0)        匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含
那些组所对应值的元组。
groups()        返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
演示如下:

#re.match.
import re
print(re.match("rlovep","rlovep.com"))##匹配rlovep
print(re.match("rlovep","rlovep.com").span())##从开头匹配rlovep
print(re.match("com","http://rlovep.com"))##不再起始位置不能匹配成功
##输出:
<_sre.SRE_Match object; span=(0, 6), match='rlovep'>
(0, 6)
None
实例二:使用group

import re

line = "This is my blog"
#匹配含有is的字符串
matchObj = re.match( r'(.*) is (.*?) .*', line, re.M|re.I)
#使用了组输出:当group不带参数是将整个匹配成功的输出
#当带参数为1时匹配的是最外层左边包括的第一个括号,一次类推;
if matchObj:
    print ("matchObj.group() : ", matchObj.group())#匹配整个
    print ("matchObj.group(1) : ", matchObj.group(1))#匹配的第一个括号
    print ("matchObj.group(2) : ", matchObj.group(2))#匹配的第二个括号
else:
    print ("No match!!")

#输出:

matchObj.group() :  This is my blog
matchObj.group(1) :  This
matchObj.group(2) :  my
3re.search方法

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

函数语法:

re.search(pattern, string, flags=0)
函数参数说明:

参数        描述
pattern        匹配的正则表达式
string        要匹配的字符串。
flags        标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.search方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法        描述
group(num=0)        匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包
含那些组所对应值的元组。
groups()        返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。

实例一:

  1. import re
  2. print(re.search("rlovep","rlovep.com").span())
  3. print(re.search("com","http://rlovep.com").span())
  4. #输出:
  5. import re
  6. print(re.search("rlovep","rlovep.com").span())
  7. print(re.search("com","http://rlovep.com").span())
  8. 实例二:

  9. import re

  10. line = "This is my blog"
  11. #匹配含有is的字符串
  12. matchObj = re.search( r'(.*) is (.*?) .*', line, re.M|re.I)
  13. #使用了组输出:当group不带参数是将整个匹配成功的输出
  14. #当带参数为1时匹配的是最外层左边包括的第一个括号,一次类推;
  15. if matchObj:
  16. print ("matchObj.group() : ", matchObj.group())#匹配整个
  17. print ("matchObj.group(1) : ", matchObj.group(1))#匹配的第一个括号
  18. print ("matchObj.group(2) : ", matchObj.group(2))#匹配的第二个括号
  19. else:
  20. print ("No match!!")
  21. #输出:
  22. matchObj.group() : This is my blog
  23. matchObj.group(1) : This
  24. matchObj.group(2) : my
  25. search和match区别:
  26. re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

  27. python爬虫小试牛刀

  28. 利用python抓取页面中所有的http协议的链接,并递归抓取子页面的链接。使用了集合和队列;此去爬的是我的网站,第一版很多bug;
  29. 代码如下:

  30. import re
  31. import urllib.request
  32. import urllib

  33. from collections import deque
  34. #使用队列存放url
  35. queue = deque()
  36. #使用visited防止重复爬同一页面
  37. visited = set()

  38. url = 'http://rlovep.com' # 入口页面, 可以换成别的
  39. #入队最初的页面
  40. queue.append(url)
  41. cnt = 0

  42. while queue:
  43. url = queue.popleft() # 队首元素出队
  44. visited |= {url} # 标记为已访问

  45. print('已经抓取: ' + str(cnt) + ' 正在抓取 <--- ' + url)
  46. cnt += 1

  47. try:
  48. #抓取页面
  49. urlop = urllib.request.urlopen(url,timeout=10)
  50. except Exception:
  51. print("超时")
  52. continue
  53. #判断是否为html页面
  54. if 'html' not in urlop.getheader('Content-Type'):
  55. continue

  56. # 避免程序异常中止, 用try..catch处理异常
  57. try:
  58. #转换为utf-8码
  59. data = urlop.read().decode('utf-8')
  60. except:
  61. continue

  62. # 正则表达式提取页面中所有队列, 并判断是否已经访问过, 然后加入待爬队列
  63. linkre = re.compile("href=['\"]([^\"'>]*?)['\"].*?")
  64. for x in linkre.findall(data):##返回所有有匹配的列表
  65. if 'http' in x and x not in visited:##判断是否为http协议链接,并判断是否抓取过
  66. queue.append(x)
  67. print('加入队列 ---> ' + x)
复制代码

结果如下:


回复 支持 反对

使用道具 举报

本版积分规则

关闭

站长推荐上一条 /1 下一条

小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

GMT+8, 2024-11-17 22:25 , Processed in 0.067411 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2024 Comsenz Inc.

快速回复 返回顶部 返回列表