数据解析与提取(3.1 用正则表达式解析和提取数据)

3.1.1 正则表达式基础1:findall()函数

import re
a = 'Hello 123 world'
result = re.findall('\d\d\d',a)
print(result)
['123']
  • 从运行结果来看,findall()函数返回的是一个包含结果的列表,而不是字符串或数字,很多初学者经常会忽略这一点。
  • 下面再通过一个例子来加深印象,代码如下:
import re
content = 'Hello 123 world 456 华小智Python基础教学135'
result = re.findall('\d\d\d',content)
print(result)
['123', '456', '135']
  • 从列表中提取某个元素
a = result[0]
  • 用print()将a打印输出,结果如下。这个输出结果虽然看着是数字,但是它实际上是字符串。
123
print(type(a))
<class 'str'>

正则表达式对应表

3.1.2 正则表达式基础2:非贪婪匹配值“(.*?)”

  • 贪婪模式为“.?”,非贪婪模式除了“.?”这种模式外,还有一种形式是“(.*?)”,它们的作用稍有不同。
  • 简单来说,“(.?)”用于提取文本A和文本B之间的内容,并不需要知道内容的确切长度和格式,但是需要知道内容位于哪两串文本之间,其基本语法格式如下:
    < center> 文本A(.
    ?)文本B < /center>
  • 下面结合findall()函数和非贪婪模式“(.*?)”进行文本提取的演示,代码如下:
import re
res = '文本A百度新闻文本B'
source = re.findall('文本A(.*?)文本B',res)
print(source)

  • 运行结果如下(注意返回的是一个列表):
['百度新闻']
  • 在实战中,一般不把匹配规则直接写在findall()函数的括号里,而是分成两行,先写匹配规则,再调用findall()函数,代码如下。原因是有时匹配规则比较长,分开写会比较清晰。
p_source = '文本A(.*?)文本B'
source = re.findall(p_source,res)
import re
res = '文本A百度新闻文本B,新闻标题文本A新浪财经文本B,文本A搜狐新闻文本B新闻网址'
p_source = '文本A(.*?)文本B'
source = re.findall(p_source,res)
print(source)
  • 运行结果如下
['百度新闻', '新浪财经', '搜狐新闻']

3.1.3 正则表达式基础3:非贪婪模式值“.*?”

  • 基本语法格式:文本C.*?文本D
  • 简单来说,“.?”用于代替文本C和文本D之间的所有内容。 之所以要使用 “.?”,是因为文本C和文本D之间的内容经常变动或没有规律,无法写到匹配规则里;或者文本C和文本D之间的内容,我们不想写到匹配规则里。
  • 下面一个简单的例子来演示“.*?”的用法,代码如下:
import re
res = '

文本C<变化的网址>文本D新闻标题

'
p_title = '

文本C.*?文本D(.*?)

'
title = re.findall(p_title,res) print(title)
['新闻标题']

3.1.4 正则表达式基础4:自动考虑换行的修饰符re.S

  • 修饰符有很多,最常用的是re.S,其作用是让findall()函数在查找时可以自动考虑换行的影响,使得非贪婪模式可以匹配换行。re.S的基本语法格式如下:
    re.findall(匹配规则,原始文本,re.S)
import re
res = '''文本A
    百度新闻文本B'''
p_source = '文本A(.*?)文本B'
source = re.findall(p_source,res,re.S)
print(source)
['\n    百度新闻']

3.1.5 正则表达式基础5:知识点补充

1.sub()函数

re.sub(需要替换的内容,替换值,原字符串)

import re
title = '双十一点燃线下经济 ”小时达“服务成阿里巴巴增长新引擎'
title = re.sub('<.*?>','',title)
print(title)
双十一点燃线下经济 ”小时达“服务成阿里巴巴增长新引擎

2.中括号“[]”的用法

  • 在正则表达式中,“.”“”“?”等符号都有特殊的含义,但是如果相匹配的就是这些符号,就需要使用中括号取消这些符号的特殊含义。例如,想要删除字符串里所有的“”号(这个操作在爬取股票名称时很常用,因为有点上市公司名称里有“*”号,爬取后需要删除),演示代码如下:
import re
company = '*华能信托'
company1 = re.sub('[*]','',company)
print(company1)
华能信托

3.1.6 案例实战:提取百度新闻的标题、网址、日期和来源

1.获取网页源代码

import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36'}
url = 'https://www.baidu.com/s?rtt=4&tn=news&wd=阿里巴巴'
res = requests.get(url,headers=headers).text
print(res)

2.编写正则表达式提取数据

(1.) 提取新闻的来源和日期

  • 网页源代码
   <span class="c-color-gray c-font-normal c-gap-right" aria-label="新闻来源:民生报道">民生报道</span>
    <span class="c-color-gray2 c-font-normal" aria-label="发布于:5分钟前">5分钟前</span>
  • 根据上述规律,编写出用正则表达式提取来源和日期的代码如下:
import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36'}
url = 'https://www.baidu.com/s?rtt=4&tn=news&wd=阿里巴巴'
res = requests.get(url,headers=headers).text
#print(res)

import re
p_date = '= 'date = re.findall(p_date,res)
source = re.findall(p_source,res)
print(date)
print(source)
  • 结果如下:
['发布于:今天">今天', '发布于:21分钟前">21分钟前', '发布于:24分钟前">24分钟前', '发布于:27分钟前">27分钟前', '发布于:今天">今天', '发布于:今天">今天', '发布于:1小时前">1小时前', '发布于:1小时前">1小时前', '发布于:1小时前">1小时前']
['新闻来源:天下网商">天下网商', '新闻来源:网易">网易', '新闻来源:搜狐网">搜狐网', '新闻来源:民生报道">民生报道', '新闻来源:和讯网">和讯网', '新闻来源:和讯网">和讯网', '新闻来源:同花顺财经">同花顺财经', '新闻来源:腾讯网">腾讯网', '新闻来源:ZAKER">ZAKER', '新闻来源:新浪财经">新浪财经']

(2.)提取新闻的网址和标题

  • 源代码
<div><h3 class="news-title_1YtI1"><a href="https://baijiahao.baidu.com/s?id=1727965931596949939&wfr=spider&for=pc" target="_blank" class="news-title-font_1xS-F" aria-label="标题:阿里巴巴将回购250亿美元股票" data-click="{
            &#39;f0':'77A717EA',
            &#39;f1':'9F73F1E4',
            &#39;f2':'4CA6DE6E',
            &#39;f3':'54E5243F',
            &#39;t':'1647917225',
  • 通过观察,可以发现网址的网页源代码有如下规律:
<h3 class="news-title_1YtI1"><a href="网址"
  • 根据上述规律,编写出用正则表达式提取网页的代码如下:
import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36'}
url = 'https://www.baidu.com/s?rtt=4&tn=news&wd=阿里巴巴'
res = requests.get(url,headers=headers).text
#print(res)

import re
p_date = '= 'date = re.findall(p_date,res)
source = re.findall(p_source,res)
# print(date)
# print(source)

p_href = '

href = re.findall(p_href,res) #不存在换行,无须添加re.S print(href)

['https://www.163.com/dy/article/H32EE4RT05129QAF.html', 'http://news.10jqka.com.cn/comment/637674609.shtml', 'http://www.cnr.cn/ziben/kb/20220322/t20220322_525772916.shtml', 'http://news.sohu.com/a/531732729_120078003', 'http://www.iwshang.com/articledetail/268337', 'https://www.163.com/dy/article/H32CO3TF0550C0ON.html', 'http://news.sohu.com/a/531728021_100032554', 'http://stock.hexun.com/2022-03-22/205546280.html', 'http://stock.hexun.com/2022-03-22/205546315.html', 'https://view.inews.qq.com/a/20220322A02U8U00']
  • 标题的获取稍微复杂一些。通过观察,发现包含标题的网页源代码有如下规律:
 <div><h3 class="news-title_1YtI1"><a href="https://baijiahao.baidu.com/s?id=1727965931596949939&wfr=spider&for=pc" target="_blank" class="news-title-font_1xS-F" aria-label="标题:阿里巴巴将回购250亿美元股票" data-click="{
            'f0':'77A717EA',
            'f1':'9F73F1E4',
            'f2':'4CA6DE6E',
            'f3':'54E5243F',
            't':'1647917225',
        }"><!--s-text--><em>阿里巴巴</em>将回购250亿美元股票<!--/s-text--></a></h3>
<h3 class="news-title_1YtI1">一些不关心的内容(含换行)>标题</a>
  • 根据上述规律,编写出正则表达式提取标题的代码如下:
import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36'}
url = 'https://www.baidu.com/s?rtt=4&tn=news&wd=阿里巴巴'
res = requests.get(url,headers=headers).text
#print(res)

import re
p_date = '= 'date = re.findall(p_date,res)
source = re.findall(p_source,res)
# print(date)
# print(source)

p_href = '

href = re.findall(p_href,res) #不存在换行,无须添加re.S #print(href) p_title = '

.*?>(.*?)' #用“.*?”代替不关心的内容,用“(.*?)”提取需要的内容 title=re.findall(p_title,res,re.S) #存在换行,需要添加re.S print(title)

  • 提取所需数据后,可用print()打印输出数据内容进行查看,结果如下图所示。还可以用len()函数查看获取的各项内容的条数是否一直,已验证正则表达式是否编写正确。
['阿里巴巴扩大股份回购规模至250亿美元,委任新独立董事', '阿里回购规模扩大至250亿美元,为中概股史上最大回购计划', '话题:250亿美元!阿里巴巴开启中概股史上最大规模回购', '创中概股回购规模纪录!阿里巴巴扩大股份回购规模至250亿美元', '阿里巴巴将回购250亿美元股票', '阿里巴巴扩大股份回购规模至250亿美元 或开启新一轮中概股回购热', '阿里巴巴扩大股份回购规模至250亿美元 创中概股回购新高', '港股开盘(3.22)︱恒指涨0.46% 阿里巴巴-SW(09988)高开逾3%领涨蓝筹', '阿里巴巴宣布扩大回购规模至250亿美元,创中概股回购纪录', '阿里巴巴加码股份回购 回购规模相当于近十分之一市值']
  • 可看到网址、日期、来源基本没有问题,但是标题中含有与“ ”“ ”“”“”等无用的字符串,需要进行数据清洗。

(3)数据清洗和打印输出

  • 用re库中的sub()函数删除“”等无用的字符,然后用“+”运算符将各项内容拼接起来,用print()函数打印输出,代码如下:
import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36'}
url = 'https://www.baidu.com/s?rtt=4&tn=news&wd=阿里巴巴'
res = requests.get(url,headers=headers).text
#print(res)

import re
p_date = '(.*?)'
p_source = '(.*?)'
date = re.findall(p_date,res)
source = re.findall(p_source,res)
# print(date)
# print(source)

p_href = '

href = re.findall(p_href,res) #不存在换行,无须添加re.S #print(href) p_title = '

.*?>(.*?)' #用“.*?”代替不关心的内容,用“(.*?)”提取需要的内容 title=re.findall(p_title,res,re.S) #存在换行,需要添加re.S # print(title) for i in range(len(title)): title[i] = re.sub('<.*?>','',title[i]) print(str(i+1) + '.' + title[i] + '(' + source[i] + ' '+ date[i] + ')') print(href[i])

  • 最终结果,并没有十条新闻,只是爬出了九条新闻。
Traceback (most recent call last):
  File "D:\works\python_crawl1\04.py", line 25, in <module>
    print(str(i+1) + '.' + title[i] + '(' + source[i] + ' '+ date[i] + ')')
IndexError: list index out of range
1.阿里巴巴启动中概股史上最大规模回购 背后有三大积极信号(网易 5分钟前)
https://www.163.com/dy/article/H32RDVRU0550C0ON.html
2.阿里巴巴港股涨超10%,此前宣布中概股最大规模回购计划(新浪财经 12分钟前)
https://cj.sina.com.cn/articles/view/7517400647/1c0126e47059036kgx
3.港股阿里巴巴涨超10%(东方财富网 12分钟前)
http://emwap.eastmoney.com/info/detail/202203222318789447
4.阿里巴巴涨超10%此前宣布回购额度上调至250亿美元(营口新闻网 15分钟前)
https://www.yingkounews.com/yaowen/202203/43160.html
5.阿里巴巴涨超10%,报109.3港元(网易 20分钟前)
https://www.163.com/dy/article/H32QI7UQ0539AP40.html
6.阿里巴巴午后涨超10%,贡献恒指点数超160点(中国财经时报网 52分钟前)
https://www.3news.cn/news/guonei/2022/0322/671019.html
7.话题:港股阿里巴巴股价走高涨近9%,此前宣布扩大股份回购规模至250...(同花顺财经 1小时前)
http://news.10jqka.com.cn/comment/637676515.shtml
8.阿里巴巴投资乐创互动娱乐,后者经营范围含动漫游戏开发(腾讯网 1小时前)
https://view.inews.qq.com/a/20220322A05MZW00
9.阿里巴巴云原生大数据运维平台 SREWorks 正式开源(站长之家 1小时前)
https://www.chinaz.com/2022/0322/1376715.shtml

你可能感兴趣的:(爬虫相关案例或知识,python,爬虫)