爬虫学习----解析网页

解析网页就是从服务器请求下来的网页数据中提取出我们需要的数据,常用的有三种方法:正则表达式解析网页、BeautifulSoup和lxml。

一、使用正则表达式解析网页

正则表达式就是对字符串操作的一种逻辑公式,就是用事先定义好的特定字符和这些特定字符的组合组成一个规则字符串,这个规则字符串用来表达对字符串的一种过滤逻辑。因此,当我们获得网页数据后,就需要先将数据转换为字符串,之后再用正则表达式去匹配我们需要的内容。正则表达式的规则如下:

模式 描述 模式 描述
. 匹配任意字符,除了换行符 \s 匹配空白字符
* 匹配前一个字符0次或多次 \S 匹配任意非空白字符
+ 匹配前一个字符1次或多次 \d 匹配数字,等价于[0-9]
匹配前一个字符0次或1次 \D 匹配任何非数字,等价于[^0-9]
^ 匹配字符串开头 \w 匹配字母数字,等价于[A-Za-z0-9]
$ 匹配字符串末尾 \W 匹配非字母数字,等价于[^A-Za-z0-9]
() 匹配括号内的表达式,也表示一个组 [] 用来表示一组字符

接下来,Python有三种正则表达式的匹配方法:re.match、re.search和re.findall

1. re.match方法

匹配规则是从字符串的起始位置开始匹配,只匹配一个,如果匹配不到就返回none。

# re.match方法
import re
m = re.match("www", "www.baidu.com")
print("匹配的结果:", m)
print("匹配的起始和终点位置:", m.span())
print("匹配的起始位置:", m.start())
print("匹配的终点位置:", m.end())
匹配的结果: <_sre.SRE_Match object; span=(0, 3), match='www'>
匹配的起始和终点位置: (0, 3)
匹配的起始位置: 0
匹配的终点位置: 3
# 使用正则表达式匹配
line = "Fat cats are smarter than dogs, is it right?"
m = re.match(r'(.*) are (.*?) dogs', line)
print("匹配的整句话:", m.group(0))
print("匹配的第一个结果:", m.group(1))
print("匹配的第二个结果:", m.group(2))
print("匹配的结果列表:", m.groups())
匹配的整句话: Fat cats are smarter than dogs
匹配的第一个结果: Fat cats
匹配的第二个结果: smarter than
匹配的结果列表: ('Fat cats', 'smarter than')

在匹配的正则表达式中,有(.*)和(.*?)两个表达式,?表示非贪婪模式,意思是尽可能少的匹配。

2. re.search方法

匹配规则是扫描整个字符串,并返回第一个成功匹配的字符串

m_match = re.match('com', 'www.bad,com')
m_search = re.search('com', 'www.abd.com,www.baidu.com')
print(m_match)
print(m_search)
None
<_sre.SRE_Match object; span=(8, 11), match='com'>

3. re.findall方法

匹配规则是找到所有符合正则表达式的字符串。

m_findall = re.findall('[0-9]+', '123 is 123,456 is 456')
print(m_findall)
['123', '123', '456', '456']

二、使用BeautifulSoup解析网页

BeautifulSoup可以从HTML或XML文件中提取数据,它是一个工具箱,通过解析文档为用户提供需要抓取的数据。

使用BeautifulSoup获取博客标题

import requests
from bs4 import BeautifulSoup

link = "http://www.santostang.com/"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
r = requests.get(link, headers=headers)

# 转化响应内容为soup对象
soup = BeautifulSoup(r.text, "html.parser")
# 找到代码中class为post-title的h1标签
title_list = soup.find_all("h1", class_="post-title")
for i in range(len(title_list)):
    # 提取元素a中的文字,并去掉空格
    title = title_list[i].a.text.strip()
    print("第%s篇文章的标题是:%s" % (i+1, title))
第1篇文章的标题是:4.3 通过selenium 模拟浏览器抓取
第2篇文章的标题是:4.2 解析真实地址抓取
第3篇文章的标题是:第四章- 动态网页抓取 (解析真实地址 + selenium)
第4篇文章的标题是:《网络爬虫:从入门到实践》一书勘误
第5篇文章的标题是:Hello world!

BeautifulSoup对象是一个复杂的树形结构,每一个节点都是一个Python对象。获取网页内容就是一个提取对象内容的过程。有三种提取对象的方法,分别为:遍历文档树、搜索文档树和CSS选择器。

1. 遍历文档树

文档树的遍历方法就是要一级级的去查找,比如想要获取<h3>标签。

soup.header.h3

搜索某个标签的所有子节点,可以用contents把所有子节点以列表的方式输出

soup.header.div.contents

还可以索引列表的不同索引,获得不同的内容

soup.header.div.contents[1]

children获取子标签,descendants获得子子孙孙的节点,parent方法获得父节点的内容。

for child in soup.header.div.children:
    print(child)

for child in soup.header.div.descendants:
    print(child)

a_tag = soup.header.div.a
a_tag.parent

2. 搜索文档树

使用find()和fand_all()方法进行搜索文档树。

title_list = soup.find_all("h1", class_="post-title")

3. CSS选择器

CSS选择器方法既可以作为遍历文档树的方法提取数据,也可以作为搜索文档树的方法提取数据。,可以通过tag标签逐层查找。

soup.select("header h3")
soup.select("header > h3")

这两种得到的结果是相同的。

也可以实现搜索文档树的功能,如选择以链接www.baidu.com开始的,<a>标签。

soup.select('a[href^="http://www.baidu.com/"]')

三、使用lxml解析网页

使用lxml提取网页源代码也有三种方法:XPath选择器、CSS选择器和BeautifulSoup的find()方法。使用XPath选择器来获取数据。

import requests
from lxml import etree
link = "http://www.santostang.com/"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
r = requests.get(link, headers=headers)

# 解析为lxml格式
html = etree.HTML(r.text)
# 使用xpath读取内容
title_list = html.xpath('//h1[@class="post-title"]/a/text()')
print(title_list)
['4.3 通过selenium 模拟浏览器抓取', '4.2 解析真实地址抓取', '第四章- 动态网页抓取 (解析真实地址 + selenium)', '《网络爬虫:从入门到实践》一书勘误', 'Hello world!']

//h1:代表选取所有<h1>子元素,“//”无论在什么位置,后面加上[@class="post-title"]表示选取<h1>中class为"post-title"的元素。/a表示选取<h1>子元素的<a>元素。/text()表示提取<a>元素中的所有文本。

XPath使用路径表达式可以在网页源代码中选取节点,它是在路径来选取的。

表达式 描述
nodename 选取此节点的所有子节点
/

从根节点选取

// 从匹配选择的当前节点选择文档中的节点,而不考虑他们的位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

四、BeautifulSoup爬虫实践:房屋价格数据

import requests
from bs4 import BeautifulSoup

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
for i in range(1, 11):
    link = 'https://beijing.anjuke.com/sale/p' + str(i) 
    r = requests.get(link, headers=headers)
    print("现在爬取的是第",i, "页")
    soup = BeautifulSoup(r.text, 'lxml')
    house_list = soup.find_all('li', class_="list-item")
    
    for house in house_list:
        name = house.find('div', class_='house-title').a.text.strip()
        print(name)
现在爬取的是第 1 页
钥匙房随时看随时签约!中高层电梯观景2居,有本,税少诚心卖
七家 精装两居 双南北通透 通风效果好 格局方正 明厨明卫
首付80万留北京 首开国企墅质现房 通州副中心给您一个家!
必卖后南仓南北通透两居 无公摊 精装修 有钥匙 上后南仓小学
昌平价格Wadi 8号线平西府Xi缺婚房大二居 买到就是赚到
九州,首地浣溪谷,南北双通透,精装两居,中层,不临街,诚售
合生70年住宅两居室 南北通透 看房方便 诚心出售
九州 付秋艳推荐 大兴采育 一层把边带花园 满五无税 诚售
万科幸福汇品质社区一层送超大花园满二年价格可商议业主急售
九州好房源把边大花园,南北通透,业主诚售。
万科幸福汇 急售精装 有钥匙 三居送花园 窦店中心繁华位置
磁各庄新机场沿线 首地浣溪谷 南北精装两居高原* 六环边

总结:解析网页有很多种方法,我们只需要选取一种方法,学会学精就可以,我觉得最重要的不是这些方法,而是如果通过网页检查找到对应的标签。

上一篇文章:动态网页爬取

下一篇文章:爬虫学习----数据存储

注意:本篇学习笔记,是总结唐松老师的《Python网络爬虫从入门到实践》这本书的内容,如果想了解书中详细内容,请自行购买

猜你喜欢

转载自blog.csdn.net/gyt15663668337/article/details/86241273