四种爬取页面源代码数据的方式
文章目录
1.正则表达式re匹配
1.1 导包
import re
1.2 一步到位的匹配
在这里,直接调用re.函数名(匹配规则, 匹配字符串)
# findall: 匹配字符串中所有的符合正则的内容
result = re.findall('a', '我是一个abcdefg')
print(result) # ['a']
result = re.findall(r"\d+", "我的电话号是:10086, 我女朋友的电话是:10010")
print(result) # ['10086', '10010']
# finditer: 匹配字符串中所有的内容[返回的是迭代器], 从迭代器中拿到内容需要.group()
it = re.finditer(r"\d+", "我的电话号是:10086, 我女朋友的电话是:10010")
for i in it:
# group是从匹配到的结果中拿到具体数据,而非迭代器元素
print(i.group()) # 10086 10010
# search, 找到一个结果就返回, 返回的结果是match对象. 拿数据需要.group()
s = re.search(r"\d+", "我的电话号是:10086, 我女朋友的电话是:10010")
print(s.group()) # 10086
# match是从头开始匹配,类似在正则前加上^
s = re.match(r"\d+", "10086, 我女朋友的电话是:10010")
print(s.group()) # 10086
1.3 分步匹配及示例
- re.compile来构建自己需要的正则表达式规则
obj = re.compile(r"<div class='.*?'><span id='(?P<id>\d+)'>(?P<wahaha>.*?)</span></div>", re.S) # re.S: 让.能匹配换行符
其中:
.*?代表惰性匹配,即匹配到第一个后就不再继续匹配,在爬虫中最为常见,其余详见正则表达式的使用
(?P<wahaha>.*?) # 小括号将.*?括在里面,然后?P<wahaha>表示将.*?匹配到的内容命名为wahaha,这在后续正则表达式的函数中运用很多
- 执行各种常用函数
简单举例:
# 预加载正则表达式
obj = re.compile(r"\d+")
ret = obj.finditer("我的电话号是:10086, 我女朋友的电话是:10010")
for it in ret:
print(it.group()) # 10086 10010
ret = obj.findall("呵呵哒, 我就不信你不换我1000000000")
print(ret) # 1000000000
2.bs4匹配
2.1 导包
import requests
from bs4 import BeautifulSoup
2.2 常见函数与简单示例
2.2.1 常见函数find与find_all
# 解析数据
# 1. 把页面源代码交给BeautifulSoup进行处理, 生成bs对象
resp = requests.get(url)
page = BeautifulSoup(resp.text, "html.parser") # 指定html解析器
# 2. 从bs对象中查找数据
# find(标签, 属性=值) 仅找一个
# find_all(标签, 属性=值) 找到所有匹配的
table = page.find("table", class_="hq_table") # class是python的关键字,因此用class_
table = page.find("table", attrs={"class": "hq_table"}) # 和上一行是一个意思. 此时可以避免class
# 拿到所有数据行 过滤掉表头
trs = table.find_all("tr")[1:]
for tr in trs: # 每一行
tds = tr.find_all("td") # 拿到每行中的所有td 是一个列表
name = tds[0].text # .text 表示拿到被标签标记的内容
low = tds[1].text # .text 表示拿到被标签标记的内容
avg = tds[2].text # .text 表示拿到被标签标记的内容
high = tds[3].text # .text 表示拿到被标签标记的内容
gui = tds[4].text # .text 表示拿到被标签标记的内容
kind = tds[5].text # .text 表示拿到被标签标记的内容
date = tds[6].text # .text 表示拿到被标签标记的内容
csvwriter.writerow([name, low, avg, high, gui, kind, date])
2.2.2 简单示例
# 示例2
html = """
<ul>
<li><a href="zhangwuji.com">张⽆忌</a></li>
<li id="abc"><a href="zhouxingchi.com">周星
驰</a></li>
<li><a href="zhubajie.com">猪⼋戒</a></li>
<li><a href="wuzetian.com">武则天</a></li>
</ul>
"""
from bs4 import BeautifulSoup
page = BeautifulSoup(html, "html.parser")
lis = page.find_all("li")
for li in lis:
print(li.find("a").get("href")) # get代表获取该标签下某一属性的值 text则直接调用.text
3.XPath匹配
3.1 导包
from lxml import etree
3.2 各种语法含义
xml = """
<book>
<id>1</id>
<name>野花遍地香</name>
<price>1.23</price>
<nick>臭豆腐</nick>
<author>
<nick id="10086">周大强</nick>
<nick id="10010">周芷若</nick>
<nick class="joy">周杰伦</nick>
<nick class="jolin">蔡依林</nick>
<div>
<nick>热热热热热1</nick>
</div>
<span>
<nick>热热热热热2</nick>
</span>
</author>
<partner>
<nick id="ppc">胖胖陈</nick>
<nick id="ppbc">胖胖不陈</nick>
</partner>
</book>
"""
et = etree.XML(xml) # 生成
result = et.xpath("/book") # /表示根节点
result = et.xpath("/book/name") # 中间/表示下一层
result = et.xpath("/book/name/text()") # text()表示文本
result = et.xpath("/book//nick") # //表示找所有的相应标签,即可跳所有层
result = et.xpath("/book/*/nick") # /*/表示仅跳一层 非所有层 *代表通配符
result = et.xpath("/book/author/nick[@class='jay']/text()") # [@class='jay']表示找class为jay的标签
result = et.xpath("/book/author/nick/@class") # /@class表示找nick中的class属性值
print(result)
3.3 常用函数及语法含义
from lxml import etree
html = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<ul>
<li><a href="http://www.baidu.com">百度</a></li>
<li><a href="http://www.google.com">谷歌</a></li>
<li><a href="http://www.sogou.com">搜狗</a></li>
</ul>
<ol>
<li><a href="feiji">飞机</a></li>
<li><a href="dapao">大炮</a></li>
<li><a href="huoche">火车</a></li>
</ol>
<div class="job">李嘉诚</div>
<div class="common">胡辣汤</div>
</body>
</html>
"""
et = etree.HTML(html) # 这边是解析HTML 用的HTML()
result = et.xpath('/html/body/ul/li[2]/a/text()') # ['谷歌'] li[2]表示第二个li标签,这个2是从1开始,而非从0开始
# print(result)
li_list = et.xpath('//li')
for li in li_list:
href = li.xpath('./a/@href') # ./表示当前节点
text = li.xpath('./a/text()') # ./表示当前节点
print(href, text)
4.PyQuery匹配
4.1 导包
from pyquery import PyQuery
4.2 常用函数及语法含义
# 导入PyQuery
p = PyQuery(html)
# p是一个PyQuery类型的对象,而非字符串
print(p)
# 与css选择器的语法一致
li = p("li")
print(li)
# p是一个PyQuery类型的对象,而非字符串
a = p("a")
# 可以连续选择
a = p("li")("a")
# 后代选择器 与上者一致
a = p("li a")
print(a)
# . 意味着选择类值为aaa的标签
a = p(".aaa")
a = p(".aaa a")
# # 意味着选择id值为qq的标签
a = p("#qq a")
# 我们可以用attr来选择属性值
href = p("#qq a").attr("href")
# 我们可以用text()来选择文本值
text = p("#qq a").text()
print(href)
print(text)
# 但如果我们要得到li标签下所有a标签中的href属性值,不能用以下方法
href = p("li a").attr("href")
# 只能得到一个
print(href) # result: http://www.google.com
# 我们需要使用items()方法来得到一个迭代器
items = p("li a").items()
print(items) # result:<generator object PyQuery.items at 0x00000224E0D490B0>
for item in items:
# item也是一个PyQuery对象
# print(type(item))
href = item.attr("href")
text = item.text()
print(href)
print(text)
print('------')
# 总结一下
# attr()用于获取属性值
# items()用于获取所有匹配到的标签 是一个迭代器
# text()用于获取文本信息
# html()用于获取指定标签下的所有值
div = '''
<div><a href="test">test</a></div>
'''
div = PyQuery(div)
html = div("div").html()
text = div("div").text()
print(html) # <a href="test">test</a>
print(text) # test
4.3 一些可改变HTML结构的函数
from pyquery import PyQuery
html = '''
<html>
<div class="aaa">哒哒哒</div>
<div class="bbb">嘟嘟嘟</div>
</html>
'''
p = PyQuery(html)
# 在 <div class="aaa">哒哒哒</div> 后 加入 <div class="ccc">吼吼吼</div>
p("div.aaa").after('''<div class="ccc">吼吼吼</div>\n''')
print(p)
# 在 <div class="aaa">哒哒哒</div> 内 加入 <span class="ddd">哈哈哈</span>
p("div.aaa").append('''<span class="ddd">哈哈哈</span>''')
print(p)
# 将 <div class="bbb"> 中的class属性值改为aaa
p("div.bbb").attr("class", "aaa")
# 给 <div class="aaa"> 加入新属性id,值为123456
p("div.aaa").attr("id", "123456")
print(p)
# 从 <div class="aaa"> 中移除id属性
p("div.aaa").remove_attr("id")
print(p)
# 移除类属性值为aaa的标签
p("div.aaa").remove()
print(p)