新闻中心

从爬虫到机器学习-Python网络数据分析(python网络数据挖掘)

2023-05-26
浏览次数:
返回列表

写在前面:

很多同学都听说过爬虫。实际上,熟练使用爬虫技术获取和整理数据集是机器学习的第一步。万丈高楼平地起。如果你说做一件事从入门到精通,那就一定是从爬虫到机器学习。作为入门计算机视觉的第一步,话不多说,我们开始吧。

本文使用Python 3实现,笔者于Python 3.6,Python 3.7平台调试可运行。

建议使用Anaconda 3+Python 3.5-3.7使用。更高的版本目前支持还不完善。如果你做机器学习,3.6再适合你不过了。

为什么使用Anaconda?Conda的前身是一个非常全面的库管理工具,在科学计算的学习中。人们往往关注如何快速选择需要的库实现目标,或快速切换不同的环境(conda environment)来满足不同脚本需要。而对IDE的智能调试不是很看重。Conda在一群科学家和研究人员的需求中应运而生。如今的Conda可以更方便的添加删除库文件,或者更改库甚至Python的版本,并以库和Python的不同配置产生不同的环境,相互隔离。对于科学计算的用途非常实用。喜欢使用全智能IDE如Pycharm的小伙伴也可以直接引用Conda环境。Conda套件里有一个叫Spyder的软件。本文章使用它实现。

本文介绍一种高性能自动爬虫的实现方式。可以智能判断最热点,并批量下载目标信息。

本文约 5014 字,全文阅读约需 10 分钟,对照练习仅需 20 分钟.

为了引入爬虫,让我们设想一个很有趣而常见的场景:

试想这样一种情况:老师/上司给我布置一份任务,为明天的迎新晚会和Party做准备。需要把节目清单上的歌曲下载下来,交给负责此方面的同事。我们该怎样做呢?对照歌单一个一个在搜索框里搜索-下载?不,这看起来效率并不高。

现在我们考虑着手编写爬虫了,问题是,如果我们编写一个普通得不能再普通的爬虫,你会爬到很多信息的列表。有用的,没用的···就像二十年前的搜素引擎,还不能自动根据用户兴趣度排名搜索结果。如何使他自动在爬取的目标列表里选择最准确的那一个呢?

如果有一个程序,能够实现基于给出播放列表的音乐批量下载。取缔现有的人工单个搜索,提高搜索精度。应该也会有不少的效率提升?

接下来,让我们以某云音乐为例,详细解读高性能自动爬虫。

通过分析需求,我决定将这个爬虫分为两部分。第一部分的爬虫用来通过URL解析播放列表。第二部分的爬虫用来通过播放列表里的每一条内容去匹配最优解并下载下来。哦!别忘了。平地不能起高楼,让我们一步一步来解决这个问题。

零 爬虫技术入门,与你需要知道的知识

爬虫是什么呢

网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动抓取信息的程序或者脚本。

既然网络爬虫可以自动抓取信息,那么它到底是怎么运作的呢?

在日常生活中,当我们想利用互联网获取数据时,一般是通过浏览器向服务器提交请求。接着浏览器下载网页代码,把网页代码解析或渲染成网页。而通过爬虫获取数据的途径和前面的类似:爬虫程序首先会模拟浏览器发生请求,接着同样从服务器下载网页代码。不过在这些代码中,我们的爬虫程序只会分析、提取我们需要的数据信息。然后将之放在数据库或文件中。这样大大减少了我们面对的数据量。

因此,学好爬虫技能,可为后续的 大数据分析、挖掘、深度学习 等提供重要的数据源。

那么爬虫可以做什么呢。我们第一个想到莫过于搜索引擎类的爬虫:谷歌,雅虎一类搜索引擎类的爬虫每隔几天对全网的网页扫一遍,供大家搜索查阅,各个被扫的网站大都很开心。这些网站为了提高自己在搜索结果的位置会专门编写一个Robot协议。网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取。越是大型网站,Robots协议越规范,而谷歌,百度等搜索引擎不需要特别针对这些大网站写协议。但是有些爬虫,或是为了一己私利,或是出于某些商业利益,对某一款app或某一个网页疯狂的骚扰,甚至影响了正常的业务发展。这时候那些被扫的对象就很难受了,而这些爬虫,就属于恶意的爬虫。

那么我们可以用什么语言来编写爬虫程序呢?

爬虫可以用很多种编程语言实现。比如,PHP

但是对多线程、异步支持不是很好。爬虫是属于工具性程序,对速度和效率要求比较高。

又比如java

但是java代码量很大。重构成本比较高,任何修改会导致代码大量改动。而爬虫经常要修改采集代码,这种情况下使用Java来爬虫就不太方便

那么有没有一种语言,

能够克服上面缺点来编写爬虫程序呢?

有 那就是python

Python语法优美、代码简洁、开发效率高、支持的模块多。

相关的HTTP请求模块和HTML解析模块非常丰富。

还有Scrapy和Scrapy-redis框架让我们开发爬虫变得异常简单。

Python提供丰富的库,来让我们编写程序的时候更加方便。

一 完成你的第一个爬虫

光说不练假把式,接下来让我们看看怎么编写一个爬虫程序!

在进行爬虫之前,我们要查看此网页是否有爬虫协议。

通常爬虫协议在网站后面的一个robots.txt的文件中。我们所抓取的内容要在爬虫协议中没有被禁止。以百度搜索为例:

以百度搜索举例-图

绝大多数的网站都可以通过在网址后面加 /robots.txt 来查看robots文档。

一个简单的爬虫编写思路:

我们通过编写的爬虫程序向目标站点发起请求,即发送一个包含请求头、请求体的Request 请求。(下面会写)然后。收到Request 请求的服务器如果能正常响应,那么我们就会收到一个包含html,json,图片,视频等的Response 回应,也就是网页的源代码。笔者的博客-图

3. 在接收到的源代码中利用正则表达式,第三方解析库如Beautifulsoup,pyquery等去解析html中的数据。最后根据需要,我们可以把提取到的数据保存在数据库或文件中。

哦,差点忘了。用Python实现爬虫,你需要一个好帮手-Beautiful Soup。

Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.”(来自BeautifulSoup官方描述文档)

urllib 是一个收集了多个使用URL的模块的软件包,其中:

urllib.request 打开和阅读 URLs

urllib.error 包含 urllib.request 抛出的异常

urllib.parse 用于处理 URL

urllib.robotparser 用于解析 robots.txt 文件

没看懂?没关系。让我们来看看一个简单的爬虫程序具体是怎么实现的:

巨详细注释预警!

i. 导入相关库

#首先,我们要导入urllib的request库,它可以实现向服务器发送request请求的功能 import urllib.request #之后,我们需要用re库来解析我们接收到的内容,也就是网页代码 import re #这个os库用来在本地创建一个目录,用于存放我们爬取的照片 import os

ii. 程序开始

#程序开始,我们定义一个fetch_pictures函数来实现爬虫的主要功能 def fetch_pictures(url): #首先,我们定义一个html_content变量来存放网页的HTML源代码 html_content = urllib.request.urlopen(url).read() #接下来,使用正则表达式,指定匹配的特征为<img pic_type="0" class="BDE_Image" src="(.*?)"> r = re.compile(<img pic_type="0" class="BDE_Image" src="(.*?)") #按照我们给定的匹配特征,在刚刚的html_content中盛放的网页HTML源代码中找匹配的部分 picture_url_list = r.findall(html_content.decode(utf-8)) #调用os库,新建一个文件夹,用来存放爬下来的照片 os.mkdir(photos) #切换当前的工作路径为刚刚新建的文件夹内 os.chdir(os.path.join(os.getcwd(), photos)) #我们刚刚接收到的是一个照片列表,现在我们把这个列表里的照片一张一张的保存 for i in range(len(picture_url_list)): #定义每一张照片的名字为序号+"jpg" picture_name = str(i) + .jpg #我们使用Try..Except语句来保存图片,这样做的好处是,如果在保存过程中遇到了错误,系统不会直接终止掉整个程序,而是执行except部分 #大家以后遇到一些大项目时,使用这个办法可以有效的保持整个项目更平稳的运行。 try: #使用urlretrieve根据URL将远程数据下载到本地,并将下载的照片保存为序号+"JPG" urllib.request.urlretrieve(picture_url_list[i], picture_name) #如果下载成功,显示成功下载 print("Success to download") except: #如果下载不成功,显示不成功的那张照片的详细URL。 print("Fail to download " + picture_url_list[i])

iii. 启动函数

#所有Python程序都会从这里的main函数开始 if __name__ == __main__: #从这里,我们调用一个fetch_pictures函数来抓取这个网址里的照片,这个函数是我们刚刚定义的 fetch_pictures("[图片]http://tieba.baidu.com/p/2460150866")

写完让我们看一下效果

F5 运行它。若你在Linux环境下,可以使用python3 xxx.py解释运行,若你电脑只有Python3,那可以更简单一点:python xxx.py.

爬下来的图片:

Pretty amazing, isn&amp;#39;t it ?

你很棒,欢迎来到爬虫的世界。

二 列表解析爬虫

爬虫可以处理文本和音频数据吗?

接下来,让我们讨论文字列表和媒体数据的爬取。文字列表是我们这一节要解决的问题,媒体数据放在下一节-目标最优解爬虫。心急的朋友可以略过往下看。

惯例,我们先载入各种库。我不喜欢黑洞洞的命令行。带有GUI的窗口可以让我的体验更上一层楼。这一次,我们引入wx -Python小而好用的GUI插件。它的用法我们下面来讲。import urllib.request import requests import os //这个库用来处理本地文件操作 import re //这个库用来处理正则 from bs4 import BeautifulSoup

2. 从Main函数开始。首先,我们先新建一个App窗体,并设置其可见性。之后我们定义的方法都会在窗体内部。最后,mainloop表示窗体逻辑开始执行。这适合有GUI经验的小伙伴。如果你没有,没有关系。你只需在main函数里写一个GetMusicData()就可以了。

def main(): app = wx.App(False) frame = MyFrame1(1, "Thread-1", 1) frame.Show(True) #start the applications app.MainLoop()

3. GetMusicData()

首先,定义一个musicData的空数组。并新建一个目录用于存放音乐缓存。(主要为第三部分准备)

if not os.path.exists("d:/music"): os.mkdir(d:/music)

定义getMusicData()函数返回经过BeautifulSoup解析过的播放列表文本。

建立一个tempArr空列表,用于保存歌曲信息的歌名-id对。其抽象数据结构如下所示:

tempArr=[{歌名,id},{歌名,id},{歌名,id}·····]

设置useragent为火狐浏览器,为什么要设置这个user_agent?正如上文所述,爬虫的核心原理是模拟浏览器访问。所以你需要给他指定一个header文件,让服务器误以为你是浏览器。

使用request库访问在main函数中传进去的url,并加入我们伪造的浏览器头文件。再使用beautifulsoup以lxml方法解析获取到的网页数据(webData),在解析后的文件中,使用soup.find().find_all(a)以匹配列表的特征。若有,则保存至find_list(输出的列表).

我们得到了一个充满歌曲信息的列表。对于列表中的每一个歌曲信息,我们找到它的songid,songid保存在href标签里。把每一首歌的songid和歌名保存好,返回到tempArr。这样,一个通过歌曲列表URL返回所有歌曲的名称列表的列表解析爬虫就做好了。

全文代码均通过调试,但皮一下贼乐 def getMusicData(self,url): user_agent = Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 headers = {User-Agent:user_agent} webData = requests.get(url,headers=headers).text soup = BeautifulSoup(webData,lxml) find_list = soup.find(ul,class_="f-hide").find_all(a) tempArr = [] for a in find_list: music_id = a[href].replace(/song?id=,) music_name = a.text tempArr.append({id:music_id,name:music_name}) return tempArr

达 成 成 就,

列 表 解 析 爬 虫

三 目标最优解爬虫

本实现基于requests, sys, click, re, base64, binascii, json, os, Crypto.Cipher, http库。

这些库不需要百分百理解,但最好有个8,9成的基础。实践出真知。

1.编写get_song_url()函数。

我们注意到一般最高品质的MP3都是基于320KBPS,那么自然就是320000BPS。我们把它传到参量里,作为我们希望的目标比特率。

使用post_request将歌曲的id,比特率,csrf(置空即可)post到某云音乐的播放器播放端口URL。如果成功,收到的返回结果是一个三维数组(其实就是三个一维数组合起来),其中的“data”维的第一维的"url"维就是你要下载的URL。朋友,激动吗?

都2020年了,同名的歌辣么多,你怎么知道下的就是这首歌呢?def get_song_url(self, song_id, bit_rate=320000): #这里加入了320K优先 url = http://music.163.com/weapi/song/enhance/player/url?csrf_token= csrf = params = {ids: [song_id], br: bit_rate, csrf_token: csrf} result = self.post_request(url, params) # 歌曲下载地址 song_url = result[data][0][url] # 歌曲不存在 if song_url is None: click.echo(Song {} is not available due to copyright issue..format(song_id)) else: return song_url

很多朋友这时候很自然的就会想,那我实现一个热度排序,通过统计播放量对同名歌曲列表进行排序,选最高那个解析不就好了?

Too Young...

对于一个合格的计算机科学码工,永远记住四字箴言:“不要重复造轮子”。

我们直接调用某云音乐自带的搜索接口,定义为搜索接口返回结果第一个不就可以了?

正所谓道高一尺魔高一丈,某云音乐推荐得越准,你下载得就越智能,这简直太棒了。

2. 编写search()函数

def search(self, search_content, search_type, limit=9): url = http://music.163.com/weapi/cloudsearch/get/web?csrf_token= params = {s: search_content, type: search_type, offset: 0, sub: false, limit: limit} result = self.post_request(url, params) return result

这个函数的作用我就不提了,把你获取到的数据添加进去就可以了。很简单。

那我们知道了想下载的歌名,也知道歌曲的id和url。下一步要干什么就不用我说了吧?

3. 编写get_song_by_url()函数

我强烈建议每个人在处理本地文件注意用一个判断语句,先判断文件夹存不存在,再往里面写东西。假设Python是把枪,个人经验来看,如果文件夹不存在,你硬写,枪就会爆炸,你被炸死。

我们使用song_name+.mp3来创建本地空文件。注意,如果你下载的两首歌恰好重名了,或有重名的可能,我强烈建议你在文件名前加一个序号。这样就不会重名了。

通过download_session.get函数对url进行下载,设置timeout为默认。由于session大小有限,所以我们的做法是把一个一个小音乐片段文件拼成一个大mp3.这里你需要for循环,对所有的小包,以1024为单位,连续地写入文件。

(你可以实现一个progressbar,progressbar就是歌曲的总长度,每下载一个小包,就加一截儿。直到加满。downloadsession()和progressbar()等代码你可以找到很官方的轮子,在这里不再赘述,我分享在我的GitHub)

def get_song_by_url(self, song_url, song_name, song_num, folder): if not os.path.exists(folder):#若保存路径不可用 os.makedirs(folder) fpath = os.path.join(folder, str(song_num) + _ + song_name + .mp3)#创建空mp3文件 if sys.platform == win32 or sys.platform == cygwin: valid_name = re.sub(r[<>:"/\\|?*], , song_name)#在Windows下,有些字符不被支持 if valid_name != song_name: click.echo({} will be saved as: {}.mp3.format(song_name, valid_name)) fpath = os.path.join(folder, str(song_num) + _ + valid_name + .mp3) if not os.path.exists(fpath): resp = self.download_session.get(song_url, timeout=self.timeout, stream=True) length = int(resp.headers.get(content-length)) label = Downloading {} {}kb.format(song_name, int(length/1024)) with click.progressbar(length=length, label=label) as progressbar: with open(fpath, wb) as song_file: for chunk in resp.iter_content(chunk_size=1024):#以1024为单位 if chunk: song_file.write(chunk)#连续小包写入文件 progressbar.update(1024)

到这里,你成功编写了你的第一个自动化高性能爬虫。在从爬虫到机器学习的征途中,你已经掌握了爬虫的高级网络数据分析。

下一篇文章将会介绍爬虫-Python网络数据分析的下一步:数据存储到本地后,如何进行划分,整合与数据分析 - Python本地数据分析。

如果你觉得这篇文章不错,点赞,转发。

如果你觉得我挺有点东西,请关注我。你们的支持是我创作的动力!

我的GitHub:realkris

我的其他博客:

realkris Zhang,男,山东烟台人。研究方向:计算机视觉,神经网络与人工智能。大三在读cs,本科期间著有四篇科研论文,包括两篇EI,一篇核心,和一篇IEEE在投。获奖若干。专业划水二十年。目前在准备去美国读研。我想把我对于计算机视觉的passion point、理解与大家分享,少走弯路,一起造更多的轮子。

搜索