六、学习分布式爬虫之正则表达式

正则表达式和re模块

什么是正则表达式:
通俗的理解,就是按照一定的规则,从某个字符串中匹配出想要的数据。这个规则就是正则表达式。
正则表达式语法

import re

# 匹配某个字符串
# text = 'abc'
# ret = re.match('a',text)  #从最开始的位置匹配第一个符合规则的字符或字符串
# print(ret)      #<re.Match object; span=(0, 1), match='a'>
# print(ret.group()) #a

# 点(.):匹配任意的字符(除了\n)
# text = 'abc'
# ret = re.match('.',text)
# print(ret.group()) #a

# \d:匹配任意的数字
# text = '5abc'
# ret = re.match('\d',text)
# print(ret.group()) #5

# \D:匹配任意的非数字
# text = '+abc'
# ret = re.match('\D',text)
# print(ret.group()) #+

# \s:匹配的是空白字符(包括\n,\t,\r和空格)
# text = ' abc'
# ret = re.match('\s',text)
# print(ret.group()) #

# \S:非空白字符
# text = 'abc'
# ret = re.match('\S',text)
# print(ret.group()) #a

# \w:匹配的是a-z和A-Z以及数字和下划线
# text = '6abc'
# ret = re.match('\w',text)
# print(ret.group()) #6

# \W:匹配的是和\w相反的
# text = '@abc'
# ret = re.match('\W',text)
# print(ret.group()) #@

# []组合的方式,只要满足中括号的某一项都算匹配成功
# text = '1bc'
# ret = re.match('[\d|\w]',text) #匹配数字或字母
# print(ret.group()) #@

#使用组合的方式实现\d:
# text = '1abc'
# ret = re.match('[0-9]',text)
# print(ret.group())

#使用组合的方式实现\D:
# text = 'abc'
# ret = re.match('[^0-9]',text)
# print(ret.group())

#使用组合的方式实现\w:
text = '_1abc'
ret = re.match('[0-9a-zA-Z_]',text)
print(ret.group())

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import re

# *:匹配前一个字符0次或无限次
# text = 'abc'
# ret = re.match('\w*',text)
# print(ret.group())  #abc

# +:匹配前一个字符1次或无限次
# text = 'abc'
# ret = re.match('\w+',text)
# print(ret.group())  #abc

# ?:匹配前一个字符0次或1次
# text = 'abc'
# ret = re.match('\w?',text)
# print(ret.group())  #a

# {m}:匹配前一个字符m次
# text = 'abc'
# ret = re.match('\w{2}',text)
# print(ret.group())  #ab

# {m,n}:匹配前一个字符m到n次(贪婪匹配)
text = '1+abc'
ret = re.match('\w{1,3}',text)
print(ret.group())  #1

正则表达式小案例

import re
#1.验证手机号:手机号的规则是以1开头,第二位可以是34587,后面9为可以随意
# text = '157*****414'
# res = re.match('1[34587]\d{9}',text)
# print(res.group())

#2.验证邮箱:邮箱的规则是邮箱名称使用数字、英文字符、下划线组成的,然后是@符号,后面就是域名了
# text = '********@163.com'
# res = re.match('\w+@(qq.com|163.com)',text)
# print(res.group())

#3.验证URL:URL的规则是前面是http或则是ftp加上一个冒号,再加上一个斜杠,在后面就是可以出现任意非空白字符了
# text = 'https://mpnew.csdn.net/console/article'
# res = re.match('(http|https|ftp)://\S+',text)
# print(res.group())

#4.验证身份证:身份证的规则是总共有18位,前面17位都是数字,后面一位可以是数字,也可以是小写的x或大写的x
text = '460033********361*'
res = re.match('\d{17}(\d|x|X)',text)
print(res.group())

开始、结束、贪婪、非贪婪

import re

# ^:以....开头
# text = 'hello world'
# res = re.search('^hello',text) #re.search()匹配字符串中符合规则的字符或字符串,不在乎起始位置
# print(res.group())

# $:以....结尾
# text = 'hello world'
# res = re.search('world$',text)
# print(res.group())

# |:匹配多个字符串或表达式
# text = 'hello world'
# res = re.search('hello|world',text)
# print(res.group())

# 贪婪和非贪婪
# text = '12345'
# res = re.search('\d+',text) #贪婪模式
# res1 = re.search('\d+?',text) #非贪婪模式
# print(res.group())

# 案例一:提取html标签名称
# text = '<h1>这是标题</h1>'
# res = re.search('<.+?>',text) #<h1> 非贪婪模式匹配
# resq1 = re.search('<.+>',text) #<h1>这是标题</h1> 贪婪模式匹配
# print(res.group())

#案例二:验证一个字符是不是0-100之间的数字
# 0 , 1 , 99 , 100
text = '100'
res = re.match('0$|[1-9]\d?$|100$',text)
print(res.group())

原生字符串和转义字符串

import re

#python中的转义字符
# text = 'hello\nword'   #\n换行符
# text1 = r'hello\nword' #\原生字符串
# text2 = 'hello\\nword' #\将后面具有特殊意义的字符转义成普通字符
# print(text)

#正则表达式中的转义字符
# text = 'apple price is $99,orange price is $88'
# res = re.findall('\$\d+',text) #返回一个列表
# print(res)

#原生字符串和正则表达式
text = '\cba c'
res = re.match('\\\c',text)
res1 = re.match(r'\\c',text)
print(res.group(),res1.group())

分组

import re
#分组
text = 'apple price is $99,orange price is $88'
res = re.search('.+(\$\d+).+(\$\d+)',text)
print(res.group())  #apple price is $99,orange price is $88
print(res.group(0)) #apple price is $99,orange price is $88
print(res.group(1)) #$99
print(res.group(2)) #$88
print(res.groups()) #('$99', '$88')

#group()/group(0) :获取整个正则表达式所匹配的子串
#group(1) :匹配第一个分组
#group(2) :匹配第二个分组
#groups() :匹配所有的分组

正则表达式常用函数

import re
#re.match()从最开始的位置匹配第一个符合规则的字符或字符串
# re.search()匹配字符串中符合规则的字符或字符串,不在乎起始位置
# findall:查找所有满足条件的字符串
text = 'apple price is $99,orange price is $88'
res = re.findall(r'\$\d+',text) #返回一个列表
print(res)

# sub:根据规则替换其他字符串
text = 'hello world hello china'
res = re.sub(r' ','\n',text) #返回一个列表
print(res)
html = """
<div class="job-detail">
    <p>1. 3年以上相关开发经验 ,全日制统招本科以上学历</p>
    <p>2. 精通一门或多门开发语言(Python,C,Java等),其中至少有一门有3年以上使用经验</p>
    <p>3. 熟练使用ES/mysql/mongodb/redis等数据库;</p>
    <p>4. 熟练使用django、tornado等web框架,具备独立开发 Python/Java 后端开发经验;</p>
    <p>5. 熟悉 Linux / Unix 操作系统&nbsp;</p>
    <p>6. 熟悉 TCP/IP,http等网络协议</p>
    <p>福利:</p>
    <p>1、入职购买六险一金(一档医疗+公司全额购买商业险)+开门红+全额年终奖(1年13薪,一般会比一个月高)</p>
    <p>2、入职满一年有2次调薪调级机会</p>
    <p>3、项目稳定、团队稳定性高,团队氛围非常好(汇合员工占招行总员工比例接近50%);</p>
    <p>4、有机会转为招商银行内部员工;</p>
    <p>5、团队每月有自己的活动经费,法定节假日放假安排;</p>
    <p>6、办公环境优良,加班有加班费(全额工资为计算基数,加班不超过晚上10点,平日加班为时薪1.5倍,周末加班为日薪2倍,周末加班也可优先选择调休,管理人性化)。</p>
</div>
"""
new_html = re.sub(r'<.+?>','',html)
print(new_html)

# split:根据规则分割字符串
text = 'hello world hello china'
res = re.split(r' ',text)
print(res) #['hello', 'world', 'hello', 'china']

# compile:编译正则表达式
text = 'apple price is 55.46'
r = re.compile(r'\d+\.?\d*') #先编译后查找,可以方便以后重复使用
res = re.search(r,text)
print(res.group())

#正则表达式的注释
text = 'apple price is 55.46'
res = re.search(r"""
\d+ #整数部分
\.? #小数点
\d* #小数部分
""",text,re.VERBOSE)
print(res.group())

爬取赶集网租房信息

import requests
import re

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36'
}

def parse_page(page_url):
    response = requests.get(page_url, headers=headers)
    text = response.text
    #findall()返回的是括号所匹配到的结果,多个括号就会返回多个括号分别匹配到的结果,
    # 如果没有括号就返回就返回整条语句所匹配到的结果(如regex2)。所以在提取数据的时候就需要注意这个坑。
    house_title = re.findall(r"""
        <div.+?ershoufang-list.+?<a.+?js-title.+?>(.+?)</a> #获取房源标题
        .+?<dd.+?dd-item.+?<span>(.+?)</span> #获取户型
        .+?<span.+?<span>(.+?)</span>       #获取面积
        .+?<div.+?price.+?<span.+?>(.+?)</span> #获取价格
    """,text,re.VERBOSE|re.DOTALL) #re.DOTALL设置点(.)可以匹配所有字符
    # print(house_title)
    for title in house_title:
        print(title)

def main():
    base_url = 'http://hn.ganji.com/zufang/pn{}/'
    for x in range(1,11):
        page_url = base_url.format(x)
        parse_page(page_url)
        break

if __name__ == '__main__':
    main()
    
#总结
#1.如果想要让点(.)代表所有字符,那么需要在函数后面加re.DOTALL来表示,否则不会代表\n
#2.获取数据的时候,尽量都用非贪婪模式
#3.findall()返回的是括号所匹配到的结果,多个括号就会返回多个括号分别匹配到的结果,如果没有括号就返回就返回整条语句所匹配到的结果
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章