数据解析
数据解析
- 正则解析
- xpath解析
- bs4解析
正则解析
- re.M:多行匹配
- re.S:单行匹配(*)
爬取糗事百科中的图片数据
from urllib import request
import requests
import re
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
}
pic_url = 'https://www.qiushibaike.com/pic/page/{}/'
page_num = 5
for i in range(1, page_num + 1):
pic_res = requests.get(pic_url.format(i), headers=headers)
img_url_list = re.findall(r'pic\.qiushibaike\.com/system/pictures/\d+/\d+/medium/.*jpg', pic_res.text)
for img_url in img_url_list:
img_url = r'https://' + img_url
img_name = img_url.rsplit('/', 1)[1]
img_path = 'static/qiutu/' + img_name
request.urlretrieve(img_url, img_path)
bs4解析
- 环境的安装:
- pip install lxml
- pip install bs4
- bs4解析原理:
- 实例化一个bs对象,且将页面源码数据加载到该对象中。
- 使用bs对象中封装好的属性或者方法实现标签定位
- 将定位到的标签中的文本(属性)取出
常用方法 官方文档
# 搜索文档树
soup.a # 拿到第一个X标签
soup.find() # 可以加参数过滤,name,attrs,recursive,limit,kwargs
soup.find_all()
soup.select() # CSS选择器,官方文档: https://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/#id41
# 上面的操作同样适用于标签
tag.find_parent() # 搜索当前节点的父节点
tag.parent # 获取父节点
tag.parents # 获取父节点 迭代
tag.children # 子孙标签
tag.descendants # 子子孙孙标签
tag.find_next_sibling() # 搜索当前节点的后面的节点
tag.find_previous_sibling() # 搜索当前节点的前面的节点
# 标签属性
tag.name # 标签名
tag.get_text() # 获取标签内的值,包括子子孙孙的
tag.text # text = property(get_text)
tag.string # 标签内的值 <h1>标签内的值</h1> 如果是 <h1>标签<h2></h2>内的值</h1> 则获取失败
.strings 和 stripped_strings
如果tag中包含多个字符串 [2] ,可以使用 .strings 来循环获取,内部包含很多空格,使用 stripped_strings 消除
tag.has_attr('id') # 判断是否有否属性
tag['class'] # 标签属性,tag的属性操作方法与字典一样
tag.attrs['name'] # 获取值
tag.attrs['name'] = 'content' # 设置值
爬取诗词名句网站中的三国演义小说-bs4
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
}
prefix = 'http://www.shicimingju.com'
html = requests.get('http://www.shicimingju.com/book/sanguoyanyi.html', headers=headers)
soup_sanguoyanyi = BeautifulSoup(html.text, 'lxml')
chapter_url_list = soup_sanguoyanyi.select('.book-mulu > ul > li > a')
f = open(f'static/sanguoyanyi.txt', 'w', encoding='utf8')
for i in chapter_url_list:
chapter_url = prefix + i['href']
html2 = requests.get(chapter_url, headers=headers)
soup_page = BeautifulSoup(html2.text, 'lxml')
title = soup_page.select_one('h1').text
chapter_content = soup_page.select_one('.chapter_content').text
f.write(title + '\n')
f.write(chapter_content + '\n\n')
f.close()
xpath解析
- 环境安装:
- pip install lxml
- 解析原理:
- 实例化一个etree的对象,且将页面源码数据加载到该对象中
- 调用etree对象中的xpath方法实现标签定位和数据的提取
- 在xpath函数中必须作用xpath表达式,xpath函数返回的是一个列表
Xpath 语法 更多
/ 从根路径开始找
// 从当前位置找
//div/a div的直接子节点a
//div//a div的子孙节点a
属性定位:
#找到class属性值为song的div标签
//div[@class="song"]
层级&索引定位:
#找到class属性值为tang的div的直系子标签ul下的第二个子标签li下的直系子标签a
//div[@class="tang"]/ul/li[2]/a
逻辑运算:
#找到href属性值为空且class属性值为du的a标签
//a[@href="" and @class="du"]
模糊匹配:
//div[contains(@class, "ng")]
//div[starts-with(@class, "ta")]
取文本:
# /表示获取某个标签下的文本内容
# //表示获取某个标签下的文本内容和所有子标签下的文本内容
//div[@class="song"]/p[1]/text()
//div[@class="tang"]//text()
取属性:
//div[@class="tang"]//li[2]/a/@href
代码中使用xpath表达式进行数据解析:
1.下载:pip install lxml
2.导包:from lxml import etree
3.将html文档或者xml文档转换成一个etree对象,然后调用对象中的方法查找指定的节点
2.1 本地文件:tree = etree.parse(文件名)
tree.xpath("xpath表达式")
2.2 网络数据:tree = etree.HTML(网页内容字符串)
tree.xpath("xpath表达式")
爬取58二手房的房源信息
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from lxml import etree
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
}
def func(html_text, f):
li_XP = '//ul[@class="house-list-wrap"]/li'
title_XP = './/h2[@class="title"]/a/text()'
sum_XP = './/p[@class="sum"]//text()'
unit_XP = './/p[@class="unit"]//text()'
html = etree.HTML(html_text)
li_tag_list = html.xpath(li_XP)
for li in li_tag_list:
title = li.xpath(title_XP)
sum = li.xpath(sum_XP)
unit = li.xpath(unit_XP)
title = ''.join(title)
sum = ''.join(sum)
unit = ''.join(unit)
f.write(f'{title}\t{sum}\t{unit}\n')
url = 'https://bj.58.com/shahe/ershoufang/pn{}/'
start_pag = 1
end_pag = 5
f = open('static/58ershoufang.txt', 'a', encoding='utf8')
for i in range(start_pag, end_pag + 1):
cur_url = url.format(i)
html2 = requests.get(cur_url, headers=headers)
func(html2.text, f)
f.close()
tips
-
安装xpath插件在浏览器中对xpath表达式进行验证:可以在插件中直接执行xpath表达式。Chrome:XPath Helper,开启和关闭的快捷键:
ctrl+shift+x
-
返回数据乱码
- 修改响应对象的编码格式,
response.encoding = 'utf-8'
- 一个通用性较强的格式,
text = text.encode('iso-8859-1').decode('gbk')
- 修改响应对象的编码格式,
-
爆出错误 HTTPConnectionPool(host:XX)Max retries exceeded with url:
- 请求频率太频繁,如何让请求结束后马上断开连接且释放池中的连接资源: 'Connection':'close'
- 可能ip被封,使用代理ip
-
安装 fiddler 出现无法监听 https 请求 , 解决方案 https://www.cnblogs.com/gigamesh/p/8124454.html,
如果还遇到无法手动添加证书 解决方案 http://blog.sina.com.cn/s/blog_492b7b280101bn6v.html
-
图片懒加载技术,img 标签未在可视域内是 src2 属性,加载后是 src 属性
-
chrome debug https://developers.google.com/web/tools/chrome-devtools/javascript/?hl=zh-cn
-
使用xpath获取element的整个html代码, 以及
etree.toString
中文乱码问题
from lxml import etree
html = 'html源码'
tree = etree.HTML(html)
a = tree.xpath('//div[@id="testid"]')[0]
s1 = etree.tostring(a, pretty_print=True, method='html').decode('utf8') # 将element装换为html代码,会出现中文乱码情况
s2 = etree.tostring(a, pretty_print=True, method='html', encoding='utf8').decode('utf8') # 解决方案一
s3 = etree.tostring(a, pretty_print=True, method='html').decode('utf8') # 解决方案二,使用html模块转码
import html
s3 = html.unescape(s3)
print(s1)
print(s2)
print(s3)