前言
在近期的工作代码中我遇到了一些小问题,导致了我的更新慢了不少。明天我就想把我在之前遇到的问题分享给大家,并通过一篇实战内容来教会大家,心愿各位小伙伴当前遇到相似问题的时候,能够想起我的文章,并解决问题。
明天我要分享的常识是对于xml文件的解析。
什么是XML
XML指可拓展标记语言,规范通用标记语言的子集,是一种用于标记电子文件使其具备结构性的标记语言。XML被设计用来传输和存储数据。XML是一套定义语义的标记规定,这些标记将文档的许多部件并对这些部件加以标识。他也是元标记语言,即定义了用于定义其余畛域无关的、语义的、结构化的标记语言的句法语言
Python对XML的解析
常见的XML接口次要有两种DOM和SAX,这两种接口解决XML的形式不同,当然应用的场景也不雷同。
- SAX(simple API for XML)
Python规范库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个事件并调用用户定义的回调函数来解决XML文件。
- DOM(Document Object Model)
将XML数据在内存中解析成一个树,通过对树的操作,来操作XML。
本次分享中应用的XML文件为movies.xml,内容如下:
<collection shelf="New Arrivals"><movie title="Enemy Behind"> <type>War, Thriller</type> <format>DVD</format> <year>2003</year> <rating>PG</rating> <stars>10</stars> <description>Talk about a US-Japan war</description></movie><movie title="Transformers"> <type>Anime, Science Fiction</type> <format>DVD</format> <year>1989</year> <rating>R</rating> <stars>8</stars> <description>A schientific fiction</description></movie> <movie title="Trigun"> <type>Anime, Action</type> <format>DVD</format> <episodes>4</episodes> <rating>PG</rating> <stars>10</stars> <description>Vash the Stampede!</description></movie><movie title="Ishtar"> <type>Comedy</type> <format>VHS</format> <rating>PG</rating> <stars>2</stars> <description>Viewable boredom</description></movie></collection>
就目前来说,咱们比拟罕用的解析形式是应用DOM模块进行解析。
Python解析XML示例
from xml.dom.minidom import parseimport xml.dom.minidom# 应用minidom解析器关上XML文档DOMTree = xml.dom.minidom.parse('movies.xml') # 返回Document对象collection = DOMTree.documentElement # 获取元素操作对象# print(collection)if collection.hasAttribute('shelf'): print('Root element : %s' % collection.getAttribute('shelf'))# 在汇合中获取所有的电影movies = collection.getElementsByTagName('movie') # 返回所有的movie标签,并保留在列表中# print(movies)for movie in movies: print('*******movie******') if movie.hasAttribute('title'): print('Title: %s' % movie.getAttribute('title')) type = movie.getElementsByTagName('type')[0] print('Type: %s' % type.childNodes[0].data) # 获取标签元素的内容 format = movie.getElementsByTagName('format')[0] print('format: %s' % format.childNodes[0].data) rating = movie.getElementsByTagName('rating')[0] print('rating: %s' % rating.childNodes[0].data) description = movie.getElementsByTagName('description')[0] print('description: %s' % description.childNodes[0].data)
爱奇艺弹幕
最近出了一篇新剧,叫做《赘婿》,想必大家都看到了吧。明天咱们的实战内容就是把观众发送的弹幕抓取下来,并将我在爬取过程中遇到的内容分享给大家。
剖析网页
一般来说,视屏的弹幕是不可能呈现在网页源码中的,那么初步判断是通过异步加载弹幕数据。
首先关上开发者工具-->点击network-->点击XHR
image
找到相似上图所示的URL,咱们只须要其中的:/54/00/7973227714515400。
爱奇艺的弹幕地址获取如下:
https://cmts.iqiyi.com/bullet/参数1_300_参数2.z
参数1是:/54/00/7973227714515400
参数2是:数字1、2、3......
爱奇艺每5分钟就会加载一次弹幕,每一集下来大略是46分钟,因而弹幕的链接如下:
https://cmts.iqiyi.com/bullet/54/00/7973227714515400_300_1.zhttps://cmts.iqiyi.com/bullet/54/00/7973227714515400_300_2.zhttps://cmts.iqiyi.com/bullet/54/00/7973227714515400_300_3.z...https://cmts.iqiyi.com/bullet/54/00/7973227714515400_300_10.z
数据解码
当你把下面的URL复制到浏览器中,你会发现间接下载一个以.z为后缀的压缩包,windows不能间接关上,只能先通过Python对压缩包进行解码。
在这里我先对zlib这个库做简略的解释,zlib用于压缩和解压缩数据流。
因而,咱们能够对下载下来的数据包进行解压缩。
首先,须要以二进制的形式读取数据包,再进行解压缩。
就拿我刚刚下载下来的压缩包为例子吧。
具体代码如下所示:
import zlibwith open('7973227714515400_300_1.z', 'rb') as f: data = f.read()decode = zlib.decompress(bytearray(data), 15 + 32).decode('utf-8')print(decode)
运行后果,如下所示:
image
不晓得你有没有发现这类数据很像是XML,那咱们就无妨写多两行代码,将数据保留为XML文件。
具体代码,如下所示:
import zlibwith open('7973227714515400_300_1.z', 'rb') as f: data = f.read()decode = zlib.decompress(bytearray(data), 15 + 32).decode('utf-8')with open('zx-1.xml', 'w', encoding='utf-8') as f: f.write(decode)
失去的XML文件内容,如下所示:
image
看到运行运行后果之后是不是有点小惊喜呀,依据我下面所讲的内容就能够获取到咱们想要的数据了。
提取数据
具体代码,如下所示:
from xml.dom.minidom import parseimport xml.dom.minidomDOMTree = xml.dom.minidom.parse('zx-1.xml')collection = DOMTree.documentElemententrys = collection.getElementsByTagName('entry') for entry in entrys: content = entry.getElementsByTagName('content')[0].childNodes[0].data print(content)
运行后果,如下所示:
image
当初对网页的剖析和数据的获取思路想必大家都明确了。
那当初咱们又须要回到刚刚的终点了,须要结构弹幕URL,并向该URL发送申请,获取它的二进制数据,再进行解压缩并保留为XML文件,最初从该文件中提取弹幕数据。
结构URL
具体代码,如下所示:
# 结构URL def get_urls(self): urls = [] for x in range(1, 11): url = f'https://cmts.iqiyi.com/bullet/54/00/7973227714515400_300_{x}.z' urls.append(url) return urls
保留XML文件
具体代码,如下所示:
# 保留xml文件 def get_xml(self): urls = self.get_urls() count = 1 for url in urls: content = requests.get(url, headers=self.headers).content decode = zlib.decompress(bytearray(content), 15 + 32).decode('utf-8') with open(f'../data/zx-{count}.xml', 'a', encoding='utf-8') as f: f.write(decode) count += 1
避坑:
1、首先咱们要获取的内容其实是一个压缩包,因而咱们的headers应该这样写:
self.headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36', 'Accept-Encoding': 'gzip, deflate' }
避免出现如下谬误:
image
2、保留的xml文件不能以中文命名,还有一点就是最好增加一个 - ,如下所示:
zx-0zx-1...zx-9
避免出现如下谬误:
image
将XML文件都保留下来之后,临时正文掉爬虫代码,因为,接下来咱们须要对下面的文件进行数据提取了。
提取数据
# 提取数据 def parse_data(self): danmus = [] for x in range(1, 11): DOMTree = xml.dom.minidom.parse(f'../data/zx-{x}.xml') collection = DOMTree.documentElement entrys = collection.getElementsByTagName('entry') for entry in entrys: danmu = entry.getElementsByTagName('content')[0].childNodes[0].data danmus.append(danmu) # print(danmus) df = pd.DataFrame({ '弹幕': danmus }) return df
在这里咱们刚好应用到了,刚刚学习的XML的解析形式。所以对于咱们来说,提取外面的弹幕对咱们来说基本上,没有什么问题。
保留数据
# 保留数据 def save_data(self): df = self.parse_data() df.to_csv('../data/danmu.csv', encoding='utf-8-sig', index=False)
评论内容词云
image
小伙伴们请留神,这个只是第一集,就有两千多条弹幕,由此能够看出,这部剧还是比拟火爆的。
最初
没有什么事件是能够欲速不达的,生存如此,学习亦是如此!
因而,哪里会有什么三天速成,七天速成的说法呢?
唯有保持,方能胜利!