爬虫系列二


一切为了数据挖掘的准备
在中国大学MOOC网站上学习的北京理工大学嵩天老师的免费爬虫课程课件,简单易懂,感兴趣的戳 嵩天老师爬虫课程。侵删

六 正则表达式

编译:将符合正则表达式语法的字符串转化为正则表达式特征,只有在compile之后才算正则表达式

6.1常用操作符
操作符 说明
r 可不是用反斜杠,表示原始字符串
^ 匹配字符串开头
$ 匹配字符串的末尾
. 匹配任意字符,常用’.*’,表示匹配任意个任意字符
[…] 用来表示匹配字符的范围。常用’[a-z]’,或’[amk]’(amk中的任意一个)
[^…] 匹配不在[]中的字符:[^abc]匹配除abc外的字符
* 匹配0个或多个字符
+ 匹配1个或多个字符
? 前一个字符0次或1次扩展’abc?’,表示ab,abc
{n} 大括号前面的表达式重复n次
{n,} 重复>= n次
{n,m} 重复n到m次
a|b 匹配a或b
() 匹配括号内的表达式,表示一个组,内部只能使用
\w 匹配字母、数字、下划线[A-Za-z0-9_]
\W 匹配非字母、数字、下划线
\d 任意数字,等价于[0-9]
\D 任意非数字
\A 匹配从字符串开始
\s 匹配任意空白字符,等价于[\t\n\r\f]
\S 匹配任意非空字符

举例:

  • 整数形式的字符串(包括正负):’^-?\d+$’
  • 正整数形式的字符串:’1[0-9]*$ ’
  • 中国境内邮政编码,6位:’[1-9]\d{5}’
  • 中文字符:’[\u4e00-\u9fa5]’
  • IP地址为4段,每段0-255,
    • 0-99表达为’[1-9]?\d’,
    • 100-199:‘1\d{2}’,
    • 200-249:‘2[0-4]\d’,
    • 250-255:‘25[0-5]’.
    • 总体可以表达为’(([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5]).){3}([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])’
6.2正则表达的基本使用
import re
match = re.match(r'[1-9]\d{5}', str)
if match: #判断是否有匹配结果,否则会报错
    match.group(0)
6.2.1 表示类型
  • raw string类型,原生字符串类型,指不包含对转义字符再次转义的字符串,表示为: r’[1-9]\d{5}’
  • string类型,表示为:’[1-9]\\d{5}’
6.2.2 re库主要功能函数
  • re.search(pattern,string,flags=0),
    扫描整个字符串并返回第一个成功的匹配,返回一个match对象,否则返回none

    • pattern:正则表达式的字符串
    • string:待匹配的字符串
    • flags:控制标志,多个标志可以用’|'指定,,如re.I|re.M
      • re.I,忽略正则表达式的大小写,[A-Z]能匹配小写字母
      • re.M,表达式中的’^'操作符能将给定字符串的每行当作匹配开始
      • re.S,使用’.'匹配所有字符,原本默认匹配除换行外的所有字符
  • re.match(pattern, string, flags = 0),
    从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功,返回none

  • re.findall(pattern, string, flags = 0),搜索字符串,以列表类型返回全部能匹配的字串

  • re.split(pattern, string[,maxsplit=0,flags=0]),
    字符串按照正则表达式的结果进行分隔,返回列表类型。

    • 被匹配的部分去除掉,只剩下没有被匹配的部分分割开
    • 可以设置最大分割次数,当能被匹配的数目超过设置的最大次数时,超过分割数的部分作为整体分隔开
    >>> re.split(r'[1-9]\d{5}','BIT100081 TSU100084')
    ['BIT', ' TSU', '']
    >>> re.split(r'[1-9]\d{5}','BIT100081 TSU100084',maxsplit=1)
    ['BIT', ' TSU100084']
    
  • re.finditer(),找到所有的匹配对象,并作为迭代器返回,每次迭代都返回一个match对象

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

例:

it = re.finditer(r"\d+","12a32bc43jf3") 
for match in it: 
    print (match.group() )
  • re.sub(pattern,repl,string,count=0,flags=0),
    检索和替换,返回替换后的字符串
    • pattern:正则中的字符串
    • repl:替换的字符串,也可以是个函数
    • string:要被查找替换的原始字符串
    • count:模式匹配后替换的最大次数,默认为0替换所有的匹配
6.2.3 re.compile
regrex = re.compile(pattern,flags)
  • regrex.search()
  • regrex.match()
  • regrex.findall()
  • regrex.split()
  • regrex.finditer()
  • regrex.sub()
6.3.re库的Match对象

match对象是一次匹配的结果,包含匹配的很多信息

6.3.1 Match对象的属性:
  • .string,待匹配的文本
  • .re,匹配时使用的pattern
  • .pos,搜索文本的开始位置
  • .endpos,所有文本的结束位置
6.3.2 对象的方法(用findall试试)
  • .group(0)
  • .groups()
  • .start(),匹配字符串在原始字符串中的起始位置
  • .end(),匹配字符串在原始字符串中的结束位置
  • .span,返回(.start(), .end())
>>> line = "Cats are smarter than dogs"
>>> m = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
>>> m.string
'Cats are smarter than dogs'
>>> m.re
re.compile('(.*) are (.*?) .*', re.IGNORECASE|re.MULTILINE)
>>> m.pos
0
>>> m.endpos
26
>>> m.group()
'Cats are smarter than dogs'
>>> m.group(0)
'Cats are smarter than dogs'
>>> m.group(1)
'Cats'
>>> m.group(2)
'smarter'
>>> m.groups()
('Cats', 'smarter')
>>> m.start()
0
>>> m.end()
26
>>> m.span()
(0, 26)
>>> m=re.search(r'[1-9]\d{5}','BIT100081 TSU100084')
>>> m.groups()
()
>>> m.group()
'100081'
>>> m.group(0)
'100081'
6.4.贪婪匹配和最小匹配

默认贪婪匹配,匹配最长的字符串

>>> m = re.match(r'PY.*N','PYANBNCNDN')
>>> m.group(0)
'PYANBNCNDN'

当想要最小匹配时

  • *?,前一个字符0次或无限次扩展,最小匹配
  • +?,前一个字符1次或无限次扩展,最小匹配
  • ??,前一个字符0次或1次扩展,最小匹配
  • {m,n}?,扩展前一个字符m至n次,最小匹配
>>> m = re.match(r'PY.*?N','PYANBNCNDN')
>>> m.group(0)
'PYAN'

七 练习

7.1.淘宝商品爬取

目标:获取淘宝搜索页面的信息,提取其中的商品名称和价格。需要找到淘宝的搜索接口,并且处理翻页

7.1.1 思考

搜索url:“https://s.taobao.com/search?" + “商品类别”;翻页url:“https://s.taobao.com/search?"+商品类别 +”&s=” + 44*页数

User-agent: *
Disallow: /

当爬虫类人行为,可以有限制的爬取

7.1.2代码
import requests
import re
from bs4 import BeautifulSoup
#提交请求
def getHTMLText(url):
    try: 
        r = requests.get(url,timeout = 30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        print('wrong')

# 从页面中提取信息
def parsePage(ilt,html):
    try:
        plt = re.findall(r'\"view_price\"\:\"[\d\.]*\"',html) #搜索所有的价格信息
        tlt = re.findall(r'\"raw_title\"\:\".*?\"',html) #最小匹配,只取最后一个",搜索名称信息
        for i in range(len(plt)):
            price = eval(plt[i].split(':')[1]) #去掉最外层单双引号
            title = eval(tlt[i].split(':')[1])
            ilt.append([price,title])
    except:
        print(" ")     

#打印信息
def printGoodsList(ilt):
    tplt = "{:4}\t{:8}\t{:16}"
    print(tplt.format("序号","价格","商品名称"))
    count = 0
    for g in ilt:
        count = count+1
        print(tplt.format(count,g[0],g[1]))

def main():
    #商品,爬取页面的深度,url
    goods = "书包"
    depth = 2
    start_url = 'https://s.taobao.com/search?q=' + goods
    infoList = []
    #访问每个页面
    for i in range(depth):
        try:
            url = start_url + '&s=' + str(44*i)
            html = getHTMLText(url)
            parsePage(infoList,html)
        except:
            continue
    printGoodsList(infoList)

main()

  1. 1-9 ↩︎

猜你喜欢

转载自blog.csdn.net/liuerin/article/details/89150135