BeautiulSoup学习网址:Beautiful Soup 4.2.0 文档
一、方式一:正则表达式
要掌握正则表达式的常用符号,包括
- 一般字符
. 匹配任意单个字符
转义字符
[...]字符集
- 预定义字符集
d 匹配一个数字字符。等价于 [0-9]。
D 匹配一个非数字字符。等价于 [^0-9]。
s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ fnrtv]
S 匹配任何非空白字符。等价于 [^ fnrtv]
w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]
W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]
- 数量词
* 匹配前一个字符0或无限次
+ 匹配前一个字符1或无限次
? 匹配前一个字符0或1次
{m} 匹配前一个字符m次
{m,n} 匹配前一个字符m至n次
- 边界匹配
^ 匹配字符串开头
$ 匹配字符串结尾
A 仅匹配字符串开头
Z 仅匹配字符串结尾
正则表达式练习1 re.findall
text = '''2月份,各地继续落实地方调控主体责任,坚持因城施策,促进房地产市场平稳健康发展。
据初步测算,4个一线城市新建商品住宅销售价格环比上涨0.3%,涨幅比上月回落0.1个百分点。
其中:北京下降0.2%,上海和广州分别上涨0.3%和1.1%,深圳持平。
二手住宅销售价格环比上涨0.15%。其中:北京和深圳分别上涨0.2%和0.5%,上海和广州分别下降0.1%和0.2%。
31个二线城市新建商品住宅销售价格环比上涨0.7%,涨幅连续三个月相同;
二手住宅销售价格环比下降20.21%,降幅比上月扩大0.1个百分点。
35个三线城市新建商品住宅销售价格环比上涨10.4%,涨幅比上月回落0.2个百分点;
二手住宅销售价格环比上涨0.2%,涨幅与上月相同。'''
# 把上面这段话中的所有百分比数值提取出来
思路: 1. 后面是百分号结尾 2. 百分号前边一定是数字, 数字的位数不确定 ,至少有一个
import re
re.findall( r'd+.?d+%', text) #方法一
re.findall('d+.d+%' , text) #方法二
re.findall('[d.]*%', text) #方法三
正则表达式练习2
text1 = """西楼尘 看过 2018-07-02
最费力的成长留在树上的只有壳,最狰狞的伤口留在皮肤的只有疤。
7596 有用 凌睿 看过 2018-08-02
或是被第三者插足,或是不受父母待见,或是被辞退,却共同组成了最温馨家庭。
举报
4170 有用 九只苍蝇撞墙 看过 2018-06-11
那些说是枝一直致敬小津的人可以歇歇了。这次他拍了部让小津最深恶痛绝的今村昌平式的蛆虫电影。
举报
3627 有用 咯咯精 看过 2018-05-14
如果说爱你,还打你,那一定是说谎;如果爱你,就会像安藤樱一样紧紧抱住你。(沉溺于安藤樱的美色无法自拔
举报
3347 有用 姨妈的鸭 看过 2018-06-23
比起放下手机,这本电影在观影时需要观众做的第一步是:放下三观。"""
#提取“有用”前面的数字
re.findall(r"(d+) 有用" , text1)
#提取 数字+“有用”
re.findall(r"d+ 有用" , text1)
#提取日期
re.findall(r"d{4}-d{2}-d{2}",text1)
#把年月日分开
r1 = re.findall(r'(d+)-(d+)-(d+)', text1)
#提取用户名
re.findall(r"(S+) 看过",text1)
正则表达式练习3 提取天猫超市狗粮重量(t.findall、t.extractall)
![15acd9660c7e5cb33c9ef9b1e1d0c390.png](https://i-blog.csdnimg.cn/blog_migrate/8ac86a7a7242fde7a5a83d603b2bf78a.jpeg)
import pandas as pd
df = pd.read_excel('Product_details_test.xlsx')
t = df.TradeName.str
![5cd5bc19ab89405a62011176d56df27f.png](https://i-blog.csdnimg.cn/blog_migrate/d46a0d125df10b37df41b1c446a28d62.jpeg)
t.findall(r'd+k?g',flags = re.I) #这时用.findall()提取出来的重量是列表
![6c72f051d582f3fd0009b175a80a6c18.png](https://i-blog.csdnimg.cn/blog_migrate/ae915450e572e2e88e595800c0c28471.jpeg)
result_1 = t.extractall(r'(d+k?g)',flags = re.I) # 自动添加一列索引列
![de91058e17d678414c9996ae48ac2a22.png](https://i-blog.csdnimg.cn/blog_migrate/bfc05d78344115ee947cd5503a9b38bd.jpeg)
result = t.extract(r'(d+)(k?g)',flags = re.I) # 重量和单位分开
![fbedb1d675f29fa9b577a0f50a85607d.png](https://i-blog.csdnimg.cn/blog_migrate/27d1512489a8a245853c9c12cb907816.png)
result_2 = t.extract(r'(d+k?g)',flags = re.I) # 重量和单位在一列
![07997400470801397a7c6ca1923a34b8.png](https://i-blog.csdnimg.cn/blog_migrate/baef31a18b3f491695e956d3be0dc0ea.png)
注意:
- - pandas 中str属性支持正则表达式的方法整理
- - contains 包含,返回bool类型, 包含规则返回真,否则返回假
- - extract 按组提取, 必须加括号分组, 提取出匹配出来的第一个数据
- - extractall 按组提取, 必须加括号分组, 提取出匹配到的所有数据
- - findall 提取出匹配到的所有数据, 默认返回列表
爬取网络小说的逻辑:
1. 先爬取每一章节的链接
2. 测试其中一章节的爬取
3. 使用循环爬取所有的章节, 分别储存到一个txt文件中
4. 可以再试一下, 把整部小说保存到一个文档中去.
二、案例1:爬取剑来小说 (利用正则表达式解析)
网址:http://www.shuquge.com/txt/8659/index.html
思路:
1. 从目录页里面把所有的章节列表链接提取出来
2. 先随便找一个章小说, 爬取测试
3. 把代码组合成函数, 抓取一章内容的函数命名为get_one_page_content() 编写保存到本地文件的功能.
4. 对chapter_link中的每一个连接进行循环, 调用get_one_page_content()获取到章节的标题和章节的内容
5. 将标题和内容保存下来
6. 对所有的章节遍历保存整部小说
做法:
第1步:定义一个函数,实现功能: 传进去一个链接, 返回的小说标题、内容
def get_one_page_content(url):
"""功能: 传进去一个链接, 返回的就是小说的名称还有小说的内容"""
import requests
import re
# 添加Hearder
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
# 先随便找一个章小说, 爬取测试
r = requests.get(url ,headers = headers)
# 改变编码
r.encoding = r.apparent_encoding
# 提取标题
title = re.findall(r'<h1>(.*)</h1>', r.text)[0]
# 懒惰模式匹配文章主题内容, 提取文本内容
content = re.findall(r'<div id="content" class="showtxt">(.*?)</div>', r.text, flags=re.S)[0].replace(' ','').replace('<br/>','n')
return title, content
难点:提取标题和内容(正则表达式部分)
技巧:点开某一章节,光标放在标题,右键-审查元素(找标题的位置)
![d5e9d3a10303c7dbd8555f0b55eccafb.png](https://i-blog.csdnimg.cn/blog_migrate/ee486dddd706219aabf0c5236d7cf2b4.jpeg)
技巧:点开某一章节,光标放在正文,右键-审查元素(找正文的位置)
![b7334de60fe6c6cb7ab29d005f1608b9.png](https://i-blog.csdnimg.cn/blog_migrate/ae566809debb1cc30a5d80aa6b164ff5.jpeg)
第2步:定义第2个函数,实现功能: 传入一本小说网址, 返回小说章节列表
def get_novel_chapter_link(url):
"""功能: 传入一本小说网址, 返回小说章节列表"""
import requests
import re
# 添加Hearder
headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
#
r = requests.get(url ,headers = headers)
# 改变编码
r.encoding = r.apparent_encoding
# 编写正则表达式进行匹配, 提取章节列表
chapter_link = re.findall(r'<dd><a href="(.*)".*</dd>' , r.text)
return chapter_link
第3-1步:实现功能:传入一本网络小说的网址,小说每一章节都独立保存为一个txt文件,到本地文件夹“剑来小说”
# 1. 获取章节列表 http://www.shuquge.com/txt/8659/index.html
chapter_link = get_novel_chapter_link("http://www.shuquge.com/txt/8659/index.html")
import requests
import os
import re
if not os.path.exists('剑来小说'):
os.mkdir('剑来小说')
# 2. 对chapter_link 中的链接进行遍历
basic_link = "剑来"
n = 1 # 开始数字
for one_link in chapter_link:
# 网址的拼接操作
complete_link = basic_link + one_link
# 调用爬取一章内容的函数
title, content = get_one_page_content(complete_link)
f = open('./剑来小说/'+ str(n) +'.'+title+'.txt', 'w' ) # 进入下层目录 title 和 .txt
f.write(content) # 写入小说内容
f.close() # 关闭文件
print('已完成章节:', title)
n += 1
![9071668c83a7107f484ba72d97dfb547.png](https://i-blog.csdnimg.cn/blog_migrate/bd7d393a63f775daedb705a735faa1e6.jpeg)
第3-2步:实现功能:所有章节保存到一个txt文件中
# 1. 获取章节列表 剑来
chapter_link = get_novel_chapter_link("剑来")
import requests
import os
import re
if not os.path.exists('剑来小说'):
os.mkdir('剑来小说')
# 2. 对chapter_link 中的链接进行遍历
basic_link = "剑来"
novel_content = ''
for one_link in chapter_link:
# 网址的拼接操作
complete_link = basic_link + one_link
# 调用爬取一章内容的函数
title, content = get_one_page_content(complete_link)
novel_content = novel_content+title+'nn'+content+'nn'
#循环外部
f = open('./剑来小说/'+'剑来.txt', 'w','encoding = utf-8' ) # 进入下层目录 title 和 .txt
f.write(novel_content) # 写入小说内容
f.close() # 关闭文件
三、方法二:BeautifulSoup方法
- Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.
- Beautiful Soup是一个利用HTML或者XML来对内容进行解析的, 解析库
- HTML的属性都具有结构上的层级关系, 而且有css和id属性, Beautiful Soup就是利用这样的关系进行 提取
![4fe0179117d523ad0eb646c41ff94fd9.png](https://i-blog.csdnimg.cn/blog_migrate/d606359cfb2c71708df16229e4a90a37.jpeg)
import requests
from bs4 import BeautifulSoup
BeautifulSoup库的练习1:诛仙小说
url = "https://www.ibiquge.net/40_40039/19832200.html"
headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
r = requests.get(url)
r.encoding = r.apparent_encoding
r
# 利用BeautifulSoup 这个类 ,把源代码创建成 Beautifulsoup 对象
bs = BeautifulSoup(r.text , 'lxml') # 两个参数 1. 把源代码字符串放进去 2 . 解析器
![0ded4e621da32d4b0d9f79e6b3dc5d97.png](https://i-blog.csdnimg.cn/blog_migrate/ef150648573c8e9ad3084bf811094644.jpeg)
![d3681758d7fe3bb47ecaa207bf31b15d.png](https://i-blog.csdnimg.cn/blog_migrate/6f18c6e0c60e0bab158d5198e5c9d771.jpeg)
url = "https://www.ibiquge.net/40_40039/"
headers ={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'}
r = requests.get(url)
r.encoding = r.apparent_encoding
bs = BeautifulSoup(r.text, 'lxml')
![40b17865e89de31617f7c5bfb2bcd5f8.png](https://i-blog.csdnimg.cn/blog_migrate/30f7c58cc43a133db4835b5591c65a00.jpeg)
练习2:童话故事
html = """<html>
<head><title>标题:睡前故事</title></head>
<body>
<p class="title" id="alice">
<b>睡前故事</b>
<i>
作者:佚名
</i>
<i>
年代:未知
</i>
<i>
动机:讲故事
</i>
</p><div>
<a class="littleboy" href="http://example.com/bek" id="link0">罗恩</a>,
</div>
<div class="good">
<p class="story">很久很久以前, 有三个小女孩; 她们的名字分别叫做
<a class="sister" href="http://example.com/elsie" id="link1">爱丽丝</a>,
<a class="brother" href="http://example.com/lacie" id="link2">莱希</a> and
<a class="sister" href="http://example.com/tillie" id="link3">蒂莉</a>;
她们居住在井底.</p>
</div>
<p class="story">接下来故事马上就要开始了, 让我们一起走进她们的冒险故事! </p>
</body>
</html>"""
bs = BeautifulSoup(html, 'lxml')
bs.find_all('body') #获取主体部分
bs.find_all('a') #获取链接
bs.find_all(text = '罗恩') #获取文本
bs.find('a' , text = re.compile('爱')) #获取包含某部分文本的内容
bs.find_all('a', class_='brother') #指定class属性
bs.find_all('a', 'brother') #指定class属性
bs.find_all('a','sister')#指定class属性
bs.find_all('a', id='link3') #指定id属性
bs.find_all('a', href="http://example.com/bek") #指定href
![7e1faca019c76f5e16d6c2105da26df9.png](https://i-blog.csdnimg.cn/blog_migrate/70bed4c1383ad756457bc2f37aeeefdd.jpeg)
![b3be75dcd546680a794f366bfe52e7b8.png](https://i-blog.csdnimg.cn/blog_migrate/3609f92a1a8c53cb923c87a62bddb46a.jpeg)
正则表达式与BeautifulSoup库的结合使用
re.compile('bek')
bs.find_all('a', href=re.compile('bek')) #提取链接包含某部分的内容
bs.find('p', 'story') #指定class属性
story.findAll('a', 'brother')[0] #指定class属性
![fb84a82c3de895b15e72b3b980cec005.png](https://i-blog.csdnimg.cn/blog_migrate/3a8e03bf28f929795732a7a4f86b79fe.jpeg)
![24872120c1aae6348efffe299ce45e55.png](https://i-blog.csdnimg.cn/blog_migrate/719f2a628f07dbcfe38fa6d996e97dfb.jpeg)
四、案例:爬取哪吒之魔童降世电影的短评(利用Beautiful库解析)
哪吒之魔童降世 短评movie.douban.com定义函数:实现功能:输入一页短评地址,将短评、有用人数、评论时间、用户名、用户主页、用户头像返回到一个DataFrame中
![779ab52531a3d9412b749f561318b656.png](https://i-blog.csdnimg.cn/blog_migrate/b75907424c29102345ca8e7eff5e11e5.jpeg)
def get_one_page_short(url):
import requests
import pandas as pd
from bs4 import BeautifulSoup
r = requests.get(url , headers= headers)
bs = BeautifulSoup(r.text,'lxml')
# 短评
short = []
for i in bs.find_all('span', 'short'):
short.append(i.text)
# 有用人数
votes = []
for i in bs.find_all('span', 'votes'):
votes.append(i.text)
# 评论时间
comment_time = []
for i in bs.find_all('span', 'comment-time'):
comment_time.append(i.text.strip())
# 用户名
username = []
for i in bs.find_all('span', 'comment-info'):
username.append(i.find('a').text)
# 用户主页
index = []
for i in bs.find_all('span', 'comment-info'):
index.append(i.find('a')['href'])
# 用户头像
img = []
for i in bs.find_all('div', 'avatar'):
img.append(i.find('img')['src'])
# 先新建一个空的DataFrame
df = pd.DataFrame()
df['用户名'] = username
df['评论时间'] = comment_time
df['有用人数'] = votes
df['评论内容'] = short
df['用户主页'] = index
df['用户头像'] = img
return df
![5648e008f01dd9f961983b342d876eb8.png](https://i-blog.csdnimg.cn/blog_migrate/4c135e3a9cea6b00bc7d5cbfb6f8d8f5.jpeg)
五、从DataFrame中导出用户头像图片链接,保存到本地
n = 1
import os
if not os.path.exists('用户头像'):
os.mkdir('用户头像')
for i in df.用户头像:
print(i)
r = requests.get(i , headers = headers)
f = open('./用户头像/'+str(n)+'.jpg' , 'wb')
f.write(r.content)
f.close()
n += 1