by 华能信托 王宇韬
配套书籍《Python金融大数据挖掘与分析全流程详解》
京东链接:https://item.jd.com/12568751.html(京东自营)
搜索“python金融大数据挖掘”或“王宇韬”,在淘宝、当当也可购买(京东快,淘宝便宜)。
加入学习交流群,可以添加如下微信(申请请注明缘由)
目录
第一讲:Python初了解
- Python能干什么 - 华能信托具体项目实战演示
- Python安装与编译器Pycharm安装教程
- 第一个Python程序
- 我的课程的教学理念和学习方法
第二讲:Python基础知识
- 变量、行与缩进
- 数据类型:数字与字符串
- 列表与字典
- 运算符介绍与实践
第三讲:Python最重要的三大语句详解
- If语句详解与实践
- For语句详解与实践
- While语句详解与实践
第四讲:Python函数与模块
- 函数的定义与调用
- 函数参数与返回值
- 一些基本函数的介绍
- Python模块/库介绍
第五讲:综合实战1:爬虫初尝试 - 百度新闻爬取
- 舆情监控基础-网络爬虫基本介绍
- 网页结构初步介绍
- 实战!百度新闻爬取
第六讲:爬虫进阶基础:正则表达式详解
- 正则表达式基础1
- 正则表达式基础2
第七讲:综合实战2:爬虫进阶 - 百度新闻信息分析
- 利用正则表达式提取百度新闻标题、网址、日期及来源
- 批量爬取多个公司的百度新闻及自动生成报告
- 异常处理及24小时实时爬取实战
- 大作业及后续内容
后续:Python进阶的其他应用
- Python量化金融初窥 - 小市值策略简介
- 大数据分析以及机器学习介绍 - 分词方法简介
- RPA机器处理自动化介绍 - 批量获取股票数据
- Python文字识别&人脸识别
- Python语音识别
Python软件下载地址
Anaconda(这个就是Python的安装包)&Pycharm&Wampserver网盘下载地址:
链接: https://pan.baidu.com/s/1DWJ5ptC7jrkNr5IXPkD9Rw 提取码: p8w8
课程源代码地址
链接: https://pan.baidu.com/s/10mFCo4EcrXuboRDt2DngHA 提取码: gkgu
第一讲:Python初了解
- Python能干什么 - 企业级具体项目实战演示
很多从事金融行业的人也许都会有这么一个疑问,Python到底是什么,怎么最近这么火,它又能做哪些内容呢?下面我从我做的一些具体的项目来给大家展示下Python的具体企业级项目实战。
1.1 公司及行业舆情监控
舆情监控的背后是网络爬虫技术,而爬虫技术的基石就是Python。利用Python我们可以实现对几乎所有主流网站进行监控,例如新浪财经,百度新闻,搜狐,上交所,深交所等各个门户网站,以及微信推文,微博等其他自媒体。同时可以实现24小时实时爬取,并且定时更换IP,最后将爬到的数据导入到数据库,利用机器学习来进行评分,并可视化到网站上,点击本月评分可以展示本月所有新闻。
在这个Python基础课中(第五和第七讲)我们会讲解这个项目的一部分(这个完整的项目之后我会在爬虫进阶课中来全部讲解)。
与此同时,可以利用Python来进行邮件的定时发送,每天5点定时发送舆情报告。
1.2 RPA自动化AI机器人
RPA(Robotic Process Automation)机器人流程自动化,是现在炒的比较火的一个概念,其实其原理还是比较简单的,主要就是利用编程来模拟键盘鼠标操作。下面的图是我利用RPA批量下载Wind金融终端上的各个上市公司的理财购买报告,为公司同事寻找合适的资金方提供帮助。Wind可以导出Excel,但是只能一个个导出,通过个人来下载的话,则会比较繁琐,利用Python则可以将每一次的导出通过机器来完成,非常的方便。
可以说,任何的电脑上的机械化的,流程化的操作都可以通过python来模拟完成,比如批量下载银行流水等内容。
1.3 自动下载理财PDF并进行解析归档
除了万德数据库,我还从巨潮网,深交所,上交所官网自动批量下载各个公司的理财报告PDF。同时Python可以进行PDF文本解析,筛选出合适的PDF进行归档,方便之后查看。
同理,Python也可以自动从网上下载各个公司的年报、半年报、快报来进行PDF解析,这也是智能行研以及公司研究的一个简单应用。
1.4 自动生成研究报告
有的时候需要将获取的内容整理出来,同时进行一个自动报告的生成,下面的这份Word舆情报告便是Python根据爬虫及数据库自动生成的,并且可以自动发送邮件给信托经理。而行业研究报告,利用类似的原理也可以如此生成。
1.5 量化金融研究
现在很火的量化金融的主流语言便是Python,Python可以编写各种股票策略,既可以进行模拟盘来进行交易信号提醒,也可以直接进行机器实盘交易,目前国外的量化金融发展的非常成熟,国内的量化则尚处于起步阶段,并不是非常的完善,但是也因此在其中存在很多的机会。
1.6 大数据分析与人功智能简谈
金融很多时候是和数据打交道的,但越来越海量的数据已经是人很难进行分析的,比如消费金融领域,我们需要分析各个客户的信用等级,利用Python就可以进行用户画像,通过和银行合作根据其银行流水,个人基本情况等来进行机器学习,大数据分析其信用情况,从而推断这个个体的信用评级。
AlphaGo想必大家都听过,而利用Python的深度卷积神经网络就可以达成类似的效果,人工智能的背后有着Python的影子。
- Python安装教程
Anaconda 安装Python
学习Python的第一步是什么,那自然是安装Python了,这边我们选择好评度最高的安装方法:Anaconda 安装。Anaconda 是 python 的一个发行版本。安装好了 Anaconda 就相当于安装好了 python,并且里面还集成了很多关于 python 科学计算的第三方库。比如我们需要用到的 Pandas、numpy、 scipy、 matlibplot 等。
Anaconda 的官网下载地址 https://www.anaconda.com/download/ ,或者直接百度搜索Anaconda,进入官网,选择下载即可,我们这边选择Python3.7版本,它默认是64位的电脑,如果你的电脑很旧,那可能是32位的,选择32位的即可,如果是Mac或者Linux选择相对应的版本即可。
补充知识点:2020年后的Anaconda下载
2020年后Anaconda的官网改版了,下载地址变为:https://www.anaconda.com/products/individual;选择Download,下载需要的内容即可。
以Windows为例,选择下图内容(Python3版本),Mac或Linux选择相应的第一个即可。
此外,在微信群公告里、QQ群文件里也可以下载Anaconda。
程序下载好了之后,这个我推荐不要改变默认安装路径,直接保存在C盘,防止出错,然后点击安装即可,这边有一个很重要的注意点:安装到下图这一步的时候,一定要把第一个勾给勾选上,因为这个对于初学者来说,就相当于自动配置好了环境变量,不然还得麻烦手动配置。
然后一直点Next,下面这一步是否安装额外内容选择skip即可。
其他一直选择Next即可,最后点击Finish,那python就安装完成啦。
如何检查是否安装成功,有一个检查办法,同时按住Win + R键,跳出如下弹出框,输入cmd,点击确定或按下回车。
在弹出的页面输入 conda list,如果出现如下图一样的页面,则表明Anaconda安装成功,Python的各种第三方库也都安装完成。
- 第一个Python程序及Pycharm安装
安装完Python了,大家是不是有点跃跃欲试了呢,这边我们就来完成我们第一个python程序吧。
当你安装完Anaconda之后,它已经给你安装完一些不错的编译器了(编译器就是敲入代码的软件),比如Spyder,Jupyter Notebook,我们之后会介绍一款我更加喜欢的编译器Pycharm。
这边大家先使用Spyder编译器,因为它随着Anaconda安装自动安装好了,而且有的人也挺喜欢用它的,青菜萝卜各有所爱嘛,关于Spyder和Pycharm我都会介绍一下的,其实不同编译器之间的没有太大的区别,水平高的,用txt都可以写程序,我喜欢Pycharm的原因则是单纯觉得它好看。
编译器Spyder介绍
Spyder打开方法如下:电脑左下角打开Anaconda,点击Spyder即可。
点击即可打开Spyder,显示如下界面,其中左边红色框是写代码的地方,右边红色框则是输出代码结果的地方,上方的绿色的箭头则是运行代码的标志,在Spyder里,也可以按F5来运行程序。
下面就让我们来写第一个Python程序吧,在左边输入代码的地方,在英文模式下输入:
print('hello world')
注意:输入时候必须切换到英文模式,其中单引号,双引号在python中没有区别。
然后点击上方绿色的运行按钮(或者按F5快捷键),就可以在右边看到输出结果“hello world”啦;
你可以试着把引号中的内容换成其他内容,比如你的名字,看看会输出什么代码呢。
编译器Pycharm安装(推荐安装,这应该是全网最详细的Pycharm安装教程了)
题外话:Pycharm是一款非常好的编译器,安装的时候会有些坑,初学者第一次使用的时候可能会很头疼,所以我特地录了一个非常详细的教学视频,大家可以看视频学的更好一点,如果不愿意花时间安装,那么你用Spyder来学之后的内容也是完全没有问题的。
PyCharm 也是一种 Python 的编译器,如果你嫌安装麻烦,用之前的Spyder编译器也是可以的,两者的功能是大致相同的。不过我们之后的教学都是使用Pycharm来进行讲解,因为Python界有这么一种说法,高手都用Pycharm,我们虽然是初学者,不妨都先来装一装高手。我选择Pycharm的原因,是觉得它的界面(见下图)比Spyder好看。
到官网 http://www.jetbrains.com/pycharm/download/#section=windows 下载PyCharm安装包,我们选择免费版(Community)就完全够用了。
下载完后,双击就可以安装了,安装过程中,一直选择Next和Install即可,其中这一页选择下面两项即可。
之后一直点击Next一直到最后的Finish即可,可以勾选下图的“Run PyCharm Community Edition”,然后点击Finish。
这样Pycharm就安装完成啦,不过第一次使用的时候坑会比较多,大家千万跟着我的接下来的步骤设置一下,一步步来就没问题的。下面的教程非常详细,相信每一位童鞋都能安装成功。
对于按完Finish之后的第一步:这个勾选“Do not import settings”
第二步:选择页面风格,建议选择左边默认的黑色风格。
第三步:选择辅助工具,直接跳过,啥也不需要选。
第四步:创建python文件。
第五步:文件进行命名,这一步千万记得点开Project Interpreter,勾选Existing interpreter。
然后点击最右边的,如下图:在弹出的页面中选择System Interpreter, 可以看到Interpreter变成了Anaconda3\python.exe,选择OK。
回到该页面后,点击Create即可创建新的Python Project。
第六步:关闭官方小技巧提示,等待最下面的Index缓冲完毕,它缓冲的过程其实是在配置你Python的运行环境。这个也是Pycharm第一次安装的时候一个比较让人头疼的地方,它得等Index缓冲完成后,才能顺畅地操作。第一次运行Pycharm的时候Index缓冲的时间较长,以后就好多了。
第七步:等到最下面的那个Index已经缓冲完毕后,我们可以放心的进行下一步操作啦:创建Python文件,如下图,点击之前创建的项目文件夹,然后右键,点击New,选择Python File。
将新的python文件命名为 hello world。
你之后如果要新建文件的话,一是可以在File里面选择New Project,如下图所示:
然后重复上诉步骤,注意在选Project Interpreter的时候勾选Existing interpreter。或者你直接把这个hello world的文件复制到你想要的文件夹,把它重命名一下即可。
第八步:在英文模式下输入print(‘hello world’),其中单引号双引号没有区别,但一定要在英文模式下:
print('hello world')
这时候得等之前所说的Index缓冲结束后,我们在上右击,选择Run ‘hello world’即可,这样就能成功运行程序并在下方输出hello world了。注意,如果之前说的index没有缓冲结束,你可能右击的时候还没有这个Run ‘hello world’,这个是因为你的运行环境还没有配置完毕。
之后你也可以通过点击界面右上角的绿色运行按钮,运行程序,或者按住快捷键Shift + F10也可以运行程序。不过我个人还是推荐右击文件然后选择Run ‘Python文件名’的方式来运行程序,这样对初学者来说不太容易出错。
下面再对Pycharm的另外一个字体大小的设置做一个介绍,大家点击File,选择下图的Settings。
选择Settings中的Editor,选择Font,在右边的Size里可以调节显示字体的大小。
Pycharm还有个使用小技巧,就是你在Pycharm的图标上右击,可以看到最近使用过的Python文件,之后你就可以快速访问啦,如下图所示:
Pycharm使用常见问题:
Q1:为什么我第一次打开要等很久,才能进行下一步操作?
A1:第一次打开的时候都有一小会等待缓冲的时间,特别是第一次安装的时候,当等待最下面的Index转完了之后,再进行下面的操作就没有问题啦。
Q2:为什么我重新打开Pycharm的时候会提醒我说我没有Interpreter(运行环境)?如下图所示:
这个是因为你每次重新打开Pycharm的时候,它都默认你重新建立了一个project,你的python文件是属于这个project,如果这个project没有运行环境的话,python文件也没有办法运行,那么这个时候我们就需要配置下运行环境。我们点击上图右边的Configure Python interpreter(配置Python解释器),也即配置这个project的运行环境,进入Project Interpreter的界面。或者我们点击界面左上角的File,选择Settings,也能进入设置Project Interpreter的界面,如下图所示:
在上图可以看到Project Interpreter里面显示的是No interpreter,这个就是导致你每次重新打开Pycharm之后,Pycharm总是显示你没有配置运行环境。其实本质原因是因为你Pycharm默认的运行环境是空,所以每次新建一个Project后都没有运行环境。
那么如何解决这个问题呢?首先我们讲一个治标的方法,我们进入上图中的Project Interpreter界面后,我们选择右边的按钮,然后选择
中的Show All,因为你之前已经运行成功过,所以肯定是环境存在的,只是你没有勾选而已,所以我们选择Show All来看看你的曾经用过的环境,然后选择它即可。如下图所示:
如果你这里一个运行环境都没有,那么就选择上图右边的加号,选择System Interpreter,看到右边是Anaconda\python.exe,选择Ok即可,如下图所示:
我再来讲一个治本的方法,那就是我们直接把Pycharm的默认设置给改了:点击File—点击Default settings(有的Pycharm版本里叫作Settings for New Projects):
选择Project Interpreter - 选上你安装好的interpreter,再点击右下Apply,然后点击OK退出即可。这样默认的interpreter就关联上了,如下图所示:
这里的重点是,我配置的是Default Settings(有的Pycharm版本里叫作Settings for New Projects)而不是单个项目的设置,这样以后打开Pycharm的时候就再也不用配置运行环境了,可谓一劳永逸了。
- 我的课程的教学理念和学习方法
现在是一个快节奏的社会,所以我会把课尽量讲的高效简洁,我也不会讲很多花里胡哨的技能,我会用最基本的知识点来完成各种项目,我当初学习的时候花了很多时间学的很多东西学了基本用不上,学的时候也很痛苦。所以我打算用最基础的知识来完成复杂的项目,大道至简,我会以此为原则来讲课。
关于学习方法,这边稍微提一点,传统的教学理念是日积月累,然而我个人推荐的是一个快速密集的学习方法,大量快速刺激你的脑神经,在短时间进行多次学习与复习,听课也是一样,基础课加起来也不超过5个小时,你完全可以一天粗略看完,那么第二天就可以复习,三天Python基本就算入门了,当然这个进度还是因人而异吧。根据艾宾浩斯遗忘曲线,多次的重复,不停的刺激神经元,你就很难忘记了。
同时实践很重要,学习千万不可只是光听,这样对神经元的刺激是不够的,比如学习编程,一定要自己敲代码,你可以不全部自己敲,但一定要学着在原有代码上改一些东西,比如之前的print(“hello world”),你可以改成print(“hahaha”),我不推荐全部都自己敲代码,但一定要自己动手试试。
快速密集的一个方法就是倍速播放学习,一般现在在线视频有的有倍速的功能,大家可以先1.5倍速尝试,适应了可以再加速。离线的我推荐两款倍速播放器:VLC与KMplayer,可以先1.2, 1.5, 1.8, 2倍速等慢慢尝试,后期可以尝试3倍速来复习。倍速一方面节省时间,另一方面容易保持注意力,这是这两年我考CFA和FRM等证书最重要的秘诀了。
第二讲:Python基础知识
下面就开始进行Python基础知识的正式教学,下面的内容是我经过自己的学习提炼来进行的重要知识,一些不太重要的基础知识,我就通通不讲解了,让大家学的高效且轻松。
- 变量、行、缩进与注释
下面主要讲下变量、行、缩进与注释的一些基础内容。提前说一下,在python中敲代码的时候要切换到英文模式,特别是一些标点符号,比如括号,一定要是英文模式下的括号,另外如果要输入中文,需要在中文两旁加入引号,在python中单引号和双引号没什么太大区别。
1.1 变量
所谓变量,就相当于人的一个代号,我们很多都学过一次函数y = x +1, 其中的x就是变量(叫作自变量),y也是个变量(叫作因变量)。
关于变量的命名,大家尽量用字母a,b,c,a_1,b_1等,或者自己创建的字符,不要用系统自带的函数来命名,比如说不要用print来命名,写成print = 1,这样程序就会头疼了。
Python中定义一个变量只要利用 “=”即可,比如,我们可以输入如下程序。
x = 10
print(x)
x = x + 15
print(x)
其中第一行表示将10赋值给x,第二行为打印输出x,第三行表示x加上15(这个也可以写成x += 15),第四行将新的x打印输出出来。
知识点:print其实叫做print函数,就是用来将结果输出,我们以后会经常用到这个函数来输出结果。小技巧:输入print,按一下Tab键会自动补全print后面的括号。
再啰嗦一下,一个程序运行的3个方法,方法1:你在上右击,选择run即可;方法2:点击绿色的运行按钮,
,注意这个按钮左边要是你想运行的代码;方法3:快捷键Shift + F10,也可以快速运行代码,但也是要注意此时方法2中绿色按钮左边得是你想运行的代码。
这边的白话意思就是:
将10赋值给x
打印输出x
x加上15
打印输出新的x
执行该程序,将输出如下代码:
10
25
1.2 行
在python中,一般来说,很少用逗号或者分号,代码都是一行一行写的,所以每写完一句,在句尾,我们按一下Enter键,就可以进行换行。
1.3 缩进
缩进是Python中非常重要的一个知识点,缩进的意思就是类似于Word的首行缩进,缩进的快捷键是Tab键,在if,for,while等语句中都会使用到缩进,我们先看下下面的代码:
x = 10
if x >0:
print('正数')
else:
print('负数')
这边第一行令x = 10,下面是一个之后会讲到的if语句,其实判断语句很简答,if表示“如果”,所以这边的白话意思就是:
x 等于 10
如果 x 大于 0:
打印输出 '正数'
否则:
打印输出 '负数'
在第3行和第5行的print前面就必须要有缩进,否则python会报错。
如果你要减少缩进,那么按住Shift + Tab键的话就可以撤销原来的缩进,你可以选择一片区域,按住Tab键进行缩进练习,再按住Shift + Tab键撤销原来的缩进。
1.4 注释
什么叫注释呢,就是批注,大多作为一个提示作用。在程序中,我们经常要在代码旁边添加注释,防止别人或自己以后看不懂,或者不想代码执行,但又不想把它删掉,那么把这一块代码注释掉就是最好的选择了。
在Python中,有两种主要的注释方法:
1.#这之后是注释内容
2.'''这里面是注释内容'''
你可以输入#或者’’’,或者在Pycharm中,注释的快捷键是Ctrl + /;在Spyder中,注释的快捷键为Ctrl + 1;如果你想改快捷键(一般不用改,推荐就使用Ctrl + /),对于Pycharm来说:在Settings里点击Keymap,点击Main menu,点击Code,在Folding下面,选择Comment with Line Comment(行注释),右击选择第一个Add Keyboard Shortcut(添加键盘快捷键)即可进行修改了。
对于Spyder来说,修改快捷键的方式在Tools中选择Preferences里,选择Keyboard shortcuts,找到toggle comment, 发现原来的注释键为Ctrl + 1,那么双击,然后按一下新的快捷键即可。
这边顺便提一句,我们使用pycharm的时候,有的时候会不小心点击到左边的竖栏:然后出现下图这样的红点:
这个其实是断点的意思,意思是程序执行到这一步就中断了,我的课程里不会用到这个,所以大家如果误点了,出现这个红点了,再点击它一下,它就没了。
- 数据类型:数字与字符串
这一小节的话主要讲下Python中最常用的两种数据类型:数字 & 字符串。
有的老师会把这一块讲的挺复杂,其实在我这儿就很简单,大家要知道 1 和 “1”是两种不同的数据类型即可,前者是一个数字,可以进行加减乘除的操作,而后者则是个单纯的字符串,也就是常说的文本内容。字符串的一个特点就是在它的两旁有单引号或者双引号,如下图。
不同的数据类型是不能相互运算的,比如不可以写:
a = 1 + '1'
print(a)
这样的话就会报错:不同数据类型不能相互运算
这边补充一个知识点,我们如何获取一个变量的类型呢,这边教大家一个函数:type函数,type函数可以显示变量的类型:
a = 1
print(type(a))
a = '1'
print(type(a))
这边就可以输出如下,第一个是int格式(整数格式),第二个是str格式(字符串格式)。
<class 'int'>
<class 'str'>
那么如何把字符串转成数字,或者数字转换成字符串呢?
我们重点关注把数字转换成字符串,使用str函数即可,关于这些函数,大家先依葫芦画瓢即可,用用就熟练了。
a = 1
b = str(a) #将数字转换成字符串,并赋值给变量b
c = b + '1'
print(c)
通过Str函数就可以把一个数字转换成字符串了,最后输出结果:
11
下面讲一下如何把字符串转换成数字,这个我用的非常少,只讲一个我们之后课程可能会用到把字符串转成数字的函数:int函数
a = '1'
b = int(a)
c = b + 1
print(c)
通过int函数就可以把一个字符串转换成一个数字,从而可以进行数字的加减乘除等,最后输出结果:
2
- 列表与字典
列表(list)和字典(dictionary)是用来存储内容的容器,列表在我的课程里用的非常多,而字典用的则非常少,所以列表一定要重点掌握,字典目前了解即可。
3.1 列表
列表是在我的课里非常重要的一个概念,它就像个容器,可以将不同的数据放到里面进行调用,比如说一个班级里有5名学生,那么如何把这5名学生放到一起呢,那么直接放到Python程序里是不行的,如下图,程序也会出现奇怪的颜色告诉你不要这么做。
这时需要有一个容器把他们放在一起,这个容器就叫做列表。
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
print(class1)
注意上面除了汉字,其他的标点符号都要是在英文格式下的标点符号,这里的[],千万要是英文格式下的中括号,输出代码为:
['丁一', '王二麻子', '张三', '李四', '赵五']
其中列表的格式为:
列表名 = [元素1,元素2,元素3,……]
列表里的元素可以是字符串,也可以是数字,甚至可以是另外一个列表,比如如下图,它里面就含有三种元素,数字1,字符串‘123’,和一个字列表[1, 2, 3]:
list1 = [1, '123', [1, 2, 3]]
这边再顺便提一句变量命名注意点,这边我命名成list1而不是list,是一个好的编程习惯,初学者经常会犯的一个错误就是把变量名称命名为他学到的函数名称,这个有的时候没事,有的时候就不行,所以变量命名的时候得稍微注意下,你可以随便命名,如果想用类似list这样的来命名,最好在后面加一个数字1。
列表是之后进阶课程里用的最多的了,举个例子:
在实际的舆情监控系统中,我们就经常利用列表,比如如下是我们要监控的房地产行业的几家企业,就是用列表将他们放在在一起,然后再进行接下来的操作。
其中 for 循环,可以遍历列表中的所有元素,我们用最开始的例子来做个演示:
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
for i in class1:
print(i)
for i in class1 的用大白话来说就是:
列表class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
对于class1中的所有元素i:
我们都把它打印输出出来
最后输出结果就是:
丁一
王二麻子
张三
李四
赵五
关于列表,我再介绍几个以后会经常用的知识点:
(1)统计列表的元素个数的函数:len函数
有的时候我们需要统计列表里一共有多少元素,那么使用的函数为len函数,len函数:一般为len(列表名)来获取列表里有多少元素,我们一般也叫做获取列表的长度:
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
a = len(class1)
print(a)
里面有5个元素,最后程序就会输出数字5,
5
同理,如果输入如下的程序:
list1 = [1, '123', [1, 2, 3]]
print(len(list1))
这边可以不用把 len(list1) 赋值给a,可以直接打印输出,那么之前说过里面一共有3个元素:数字1,字符串‘123’,和子列表[1, 2, 3],所以最后输出的结果为3:
3
(2)调取一个列表元素的方法
有的时候我们想要调取其中一个元素,那么列表调取也很简单,只要在列表之后加一个[序号],比如class1[1]调取的就是“王二麻子”:
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
a = class1[1]
print(a)
输出代码:
王二麻子
这边有人可能会有疑惑,这边class1[1]调取的为什么不是“丁一”呢,这边就涉及到Python中一个常用的知识点,那就是序号的第一个序号都是0,也就是说无论什么排序,第一个序号都是0,而不是1,所以只有写class1[0]的时候,输出的才是“丁一”。那么如果想输出“赵五”,写的代码就应该是print(class1[4]),当它的序号为4的时候,就表示要取第五个元素,大家可自己试一下。
(3)选取多个列表元素的方法:列表切片
如果有的时候,我们想选取列表中的几个元素,比如我想取之前class1里面的第2到第4位同学,也就是王二麻子,张三和赵四,那么该如何取呢?
列表切片的话,就是用来选取其中间的一些元素,一般格式为 列表名[序号1:序号2],比如选取王二麻子,张三和赵四,就是class1[1:4],1表示序号1,也就是第二个元素(序号0是第一个元素),4表示序号4,也就是第五个元素,有人就会奇怪了,我只要取到第4个元素,为什么还要写4,也就是取到第5个元素呢。有个注意点,这个列表切片是前闭后开的,就是说它前面的那个元素是可以取到的,也就是序号1的元素:王二麻子是可以取到的;而序号4的元素:赵五则是取不到的。
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
a = class1[1:4]
print(a)
理解了序号是从0开始,所以序号1表示第二个元素,以及列表切片是前闭后开之后,我们可以理解最后的输出结果为:
['王二麻子', '张三', '李四']
(4)列表增加元素的办法:append方法
这个在我们实战教程中,也是经常会用到的技巧,比如说之后要讲的舆情监控,我要对每一个爬取到的新闻舆情进行评分,但是我不知道其实爬了多少条新闻,那么我们就可以用append方法来把这些评分一个个加上去,而不需要知道一共有多少条新闻。
score = []
score.append(80)
print(score)
输出结果:
[80]
此时我们把代码再增加几行,更加符合实战情况:
score = []
score.append(80)
score.append(90)
score.append(70)
print(score)
输出结果如下:
[80,90,70]
(5)列表与字符串之间的转换方法
这个也是一个非常重要的知识点,虽然短时间内我们用不到这个知识点,但是它在我的Python进阶课里会有一个很重要的地位,它在文本筛选中有很大的作用,大家先了解下。
比如我要把class1 = [‘丁一’, ‘王二麻子’, ‘张三’, ‘李四’, ‘赵五’],转换成‘丁一,王二麻子,张三,李四,赵五’这么一个字符串,可以用下面的方式:
命令:””.join(列表名)
其中,引号中(单引号,双引号无所谓的)是字符之间的分割符,如“,”,“;”等等
所以想把class1里的内容都合并成一个字符串,那么就应该是“,”.join(class1),这边你也可以把逗号换成空格,那么输出的就是“丁一 王二麻子 张三 李四 赵五”。
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
a = ",".join(class1)
print(a)
输出结果如下:
丁一,王二麻子,张三,李四,赵五
字符串转为列表在我的所有项目里都用不到,不讲了。
3.2 字典
字典是另一种数据存储的方式,比如说class1里面,每个人考了数学考试,各有得分,想把他们的人名和分数一一匹配到一起,那么就需要用到字典来存储数据了。
字典的基本格式如下:
字典名 = {键1:值1,键2:值2,键3:值3……}
在字典中,每个元素都有两部分(区别于列表中一个元素只有一个部分),前一个部分,我们称之为键,后一个部分我们称其为值,中间用冒号相连。
键的话就相当于一个钥匙,值的话就相当于一个锁,一个钥匙对应一个锁,同样,一个人对应一个成绩,那么对于class1里的每个人,我们可以这么写:
class1 = {'丁一':85, '王二麻子':95, '张三':75, '李四':65, '赵五':55}
注意,上面的大括号,冒号,逗号,引号都要在英文格式下输入。
如果要提取字典中的某一个元素的值,可以通过如下格式实现:
字典名["键名"]
比如,我们想获取王二麻子的高数成绩,可以这么写class1[‘王二麻子’]:
class1 = {'丁一':85, '王二麻子':95, '张三':75, '李四':65, '赵五':55}
score = class1['王二麻子']
print(score)
这样就可以输出王二麻子的分数:95。
如果我们想把每个人的名字和分数都打印出来,可以写如下代码:
class1 = {'丁一':85, '王二麻子':95, '张三':75, '李四':65, '赵五':55}
for i in class1:
print(i)
print(class1[i])
这里的i其实是指的字典里的键,也就是‘丁一’,‘王二麻子’之类的内容,所以class1[i]输出的就是这些人分数,输出结果如下:
丁一
85
王二麻子
95
张三
75
李四
65
赵五
55
如果想把名字和分数输出在一行里面,那么可以把之前的代码稍稍改一下:
class1 = {'丁一':85, '王二麻子':95, '张三':75, '李四':65, '赵五':55}
for i in class1:
print(i + ':' + str(class1[i]))
这个有两个注意点,一个是这里的加号表示的是字符串拼接,不可以直接写
print(i + ':' + class1[i])
那么因为之前也讲过的数据类型问题,‘丁一’是个字符串,而85是个数字,他俩不能相加在一起,如果相加会报错:
所以第二个注意点是要利用之前刚刚讲过的str函数把数字85转换成字符串,写成
print(i + ':' + str(class1[i]))
那么就可以输出结果:
丁一:85
王二麻子:95
张三:75
李四:65
赵五:55
- 运算符介绍与实践
运算符主要是将数据(数字和字符串)进行运算以及连接,我的课程里以及之后教的项目里主要用到的运算符主要如下,其他一些花里胡哨的我都不会讲&用:
运算符 | 含义 |
---|---|
+ | 数字相加或者字符串拼接 |
- | 数字相减 |
* | 数字相乘 |
/ | 数据相除 |
> | 大于,如果写成>=表示成大于等于 |
< | 小于,如果写成<=表示成小于等于 |
== | 比较两个对象是否相等 |
and | 逻辑与 |
or | 逻辑或 |
not | 逻辑非 |
4.1 算术运算符
算术运算符主要用到的有:+ 、-、*、/。大家应该都能明白,不多讲。
主要讲一下加号,因为它除了能进行数字的相加外,还能进行字符串的拼接,这个在之后的爬虫教学中非常有用,先举个简单的例子:
a = 'hello'
b = 'world'
c = a + ' ' + b
print(c)
这边就可以输出:
hello world
我这儿再举个爬虫实战例子,比如百度新闻搜索华能信托,出来的网址是:
http://news.baidu.com/ns?word=华能信托&tn=news&from=news&cl=2&rn=20&ct=1
那么如果我们要监控别的公司,我们就可以把华能信托4个字换成别的字即可,比如大家可以直接把它换成阿里巴巴试试看先。
那么在python里如何做的字符串的拼接呢,我们看到其实这个网址最主要的就是华能信托这4个字,那么提前这个关键字之前的和关键字之后的内容,http://news.baidu.com/ns?word=以及&tn=news&from=news&cl=2&rn=20&ct=1;那么你只要用+号把他们和别的关键词连接在一起即可,我们来试试:
url = 'http://news.baidu.com/ns?word=' + 关键词 + '&tn=news&from=news&cl=2&rn=20&ct=1'
这样的一个处理手段是之后批量爬取各个项目公司的基础。
比如我们把这个关键词写成’阿里巴巴’,那么就可以获取阿里巴巴的百度新闻舆情。
url = 'http://news.baidu.com/ns?word=' + '阿里巴巴' + '&tn=news&from=news&cl=2&rn=20&ct=1'
就可以获取如下的网址:
http://news.baidu.com/ns?word=阿里巴巴&tn=news&from=news&cl=2&rn=20&ct=1
之后在第七章,我会利用这个知识点和函数教大家如何批量爬取各个公司的舆情。
这边简单提一句,你在网页上看到的是如上的网址,但你直接把网址从网页上复制下来,看到的可能是这么一个内容:http://news.baidu.com/ns?word=%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4&tn=news&from=news&cl=2&rn=20&ct=1;中间是一堆英文符号,而不是看到的阿里巴巴(如下图),那是因为浏览器把阿里巴巴的文字格式给转换成英文了,这个大家了解即可,你可以把那一坨%的英文换成中文的阿里巴巴即可。
4.2 比较运算符
比较运算符主要是 > , <, ==。其中用的最多的是 > , <。比如之后进阶课讲的舆情监控,进行文本分析后进行机器评分,利用比较运算符,可以筛选出我们想要的负面新闻,举个例子:
score = -10
if score < 0:
print('该新闻是负面新闻,录入数据库')
这边的score是我们已经算法算好的分数,如果它小于0,我们就把它录入数据库,这边简单的演示,我们就直接把它print出来,输出结果。
该新闻是负面新闻,录入数据库
而 == 我也简单介绍一下,它是比较两个对象是否相等,它和=不一样,=号的作用是用来赋值,比如一开始讲过的 a = 1。而 == 则是比较两个内容(比如数字)是否相等,举个例子:
a = 1
b = 2
if a == b: #注意这边是两个等号
print('a和b相等')
else:
print('a和b不相等')
这边a和b不等,随意最后输出结果为:
a和b不相等
4.3 逻辑运算符
逻辑运算符主要有:not,and,or三种。
其中用的最多的是and和or,我们还是拿项目实战来作为一个例子,比如我们要判断这个新闻它的分数是负数,并且它的年份是2018年,我们才把它录入数据库:
score = -10
year = 2018
if (score < 0) and (year == 2018):
print('录入数据库')
else:
print('不录入数据库')
这边有两个注意点,在and两个判断条件上,最好加上括号,虽然有的时候不加也没问题,但是这个是比较严谨的一个做法,而且更一目了然,而且和上面讲过的一样,year == 2018这一块,注意是两个等号。
因为这个符合分数小于0且年份属于2018,所以最后的输出结果为:
录入数据库
这边我们可以修改分数改成正数或者修改年份,看看最后跑出来的结果。
此外,如果我们把and换成or的话,那么只要满足一个条件,就可以执行下面的代码,大家也可以自己试一试。
第三讲:Python最重要的三大语句详解
标题说这三大语句是python最重要的三大语句,其实可以说下面的三大语句是几乎所有编程语言最重要的几个语句,当你学到后来,你会发现很多时候,你写来写去就是if,for,while。因为这个涉及所有编程语言的一些底层逻辑:判断 & 循环。下面我们就来详细讲解一下,其实有的内容之前已经或多或少提到过了。
- If语句详解与实践
之前已经用过很多次If函数了,这边我再做一个简单介绍和一些新内容的补充吧,If函数的底层逻辑就是用来判断,如果满足条件则执行下面的语句。
基本的语法逻辑如下,注意记得写冒号及代码前的缩进:
if 条件:
代码1
else:
代码2
其中两个注意点,之前也提过了,就是缩进与英文格式的标点符号,有的时候,你忘记缩进或者冒号是中文格式的时候,程序就会报错,不过Pycharm和Spyder都会在那一行提醒你这一行的写法有问题,所以倒也不用太担心。
现在我们再来看看之前写过这个代码,是不是会感觉清晰很多呢。
score = 100
year = 2018
if (score < 0) and (year == 2018):
print('录入数据库')
else:
print('不录入数据库')
我们下面再补充些内容,其实掌握上面的内容已经完全足够了,下面的只是作为一个知识点的补充。比如你考试考了80分,最简单的是:
score = 85
if score >= 60:
print('及格')
else:
print('不及格')
我相信现在大家看这个代码已经完全没有问题了,输出肯定是‘及格’。那如果我除了想判断是否及格外,还想看它是否优秀(大于80分),则输出‘优秀’,该怎么弄呢。
score = 55
if score >= 80:
print('优秀')
elif (score >= 60) and (score < 80):
print('及格')
else:
print('不及格')
这边唯一的一个不同,就是中间加入了一个elif,这个其实就是elseif的缩写,用来提供多个结果使用的,
其实这个我做项目的时候基本没有用过,大家简单了解下即可。
- For语句详解与实践
For语句之前有提到过一次,它的重要程度可以说仅次于If语句了,它的底层逻辑是循环,其实While的底层逻辑是循环,不过还是For用的更加普遍些。
For语句的常见使用格式为,注意记得写冒号及代码前的缩进:
for i in 区域:
代码
先举个之前讲列表的时候讲过的例子:
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
for i in class1:
print(i)
用大白话来说就是:
列表class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
对于class1中的所有元素i:
我们都把它打印输出出来
这个输出代码为:
丁一
王二麻子
张三
李四
赵五
这个i可以换成任何东西,比如你换成j,换成一个字符串,只要和下面的print()里面的内容匹配即可。
比如我们可以写:
class1 = ['丁一', '王二麻子', '张三', '李四', '赵五']
for haha in class1:
print(haha)
这样输出的结果其实是一样的。
For语句还通常与range()函数合用,range函数的话其实就是一个类似于list的东西,只不过它可能更像list的长度,你想循环多少次,在range的括号里填写几就可以,比如我写for i in range(3),那么它就是循环3次:
for i in range(3):
print('hahaha')
这个它就会输出三行‘hahaha’。
我担心大家可能会对这个for i in range(3)中的i还有疑惑,刚刚i不是代表列表里的每一个元素吗,这边这个i又是什么意思呢?这边我给大家做一个偷懒的总结:
(1)对于”for i in 区域“来说,如果说这个区域是一个列表,那么那个i就表示这个列表里的每一个元素;
(2)对于”for i in 区域“来说,如果说这个区域是一个range(n),那么那个i就表示0到n -1这n个数字,之前提到过,python中序号都是从0开始的,所以这边也是从0开始,到n - 1结束。
还有个非常重要的知识点:for i in range(5)的话,它的确会循环5次,但要注意,在python中,第一个元素的序号其实是0,所以如果我们输入如下代码:
for i in range(5):
print(i)
那么输出的结果是从0开始的,也就是0到4:
0
1
2
3
4
这时候你可能要问,这玩意有什么用?下面我就以舆情监控中的实战来给大家讲解下for语句在爬虫实战中的应用:
title = ['标题1','标题2','标题3','标题4','标题5']
for i in range(len(title)): #len(title)表示一个有多少个新闻,这里是5
print(str(i+1) + '.' + title[i]) #这个其实把字符串进行一个拼接
上面这几行代码已经很大程度就是你做项目实战用到的代码了,暂时看着有点晕也没有关系,我在教学视频里会详细介绍下的。我先用大白话来解释下这几行代码在干嘛:
爬到了一些新闻标题,放到了title这个列表里
用len(title)来获取一共有多少条新闻,并利用for和range语句来进行循环:
打印输出新闻标题,并且在前面加上序号
输出结果如下图所示:
其中有几个小注意点,
(1)range(len(title))这边就相当于range(5),因为len(title)就等于5,所以for i in range(len(title))就是循环5次,这里的i就表示数字0-4。
(2)为什么要写str(i + 1),因为我们要标序号,’标题1’是字符串形式的,而i是数字,我们讲过数字和字符串不能直接相加,所以要用str函数进行下转换。
(3)至于为什么不是str(i),而是str(i + 1)。是因为之前讲列表的时候提到过,在编程中,第一个序号都是0,比如之前列表里讲过的class1[0]表示“丁一”一样,这边如果写str(i)的话,那么输出的第一个序号就是“0.标题1”了。
(4)因为这里的i就表示数字0-4,title[i]的话,表示列表中的第i+1个元素,所以title[0]的话就表示第1个元素,title[4]就表示第5个元素。
- While语句详解与实践
While的底层逻辑也是循环,它和For的特点不一样,最大的区别是For知道循环次数,而While的话则是不清楚循环次数。
其使用格式为,注意要写冒号以及代码前的缩进:
while 条件:
要执行的的代码
举个例子给大家看下:
a = 1
while a < 3:
print(a)
a = a + 1 #或者写成 a += 1
它白话的意思就是:
首先将1赋值给a
当 a 小于3的时候:
打印输出a
a 在原来的基础上加上1
a一开始等于1,满足小于3的条件,会打印输出1,然后a加上1等于2,此时a仍然小于3,所以仍然会执行打印输出的命令,此时打印输出2,然后a在2的基础上加上1等于3,此时a已经不满足小于3的条件了,那么循环此时便终止了。最后输出如下:
1
2
大家可以试着把数字3换成别的数试试看。
其实我们之后大多情况下用到While的时候,就是让While来一直循环(如果用for i in range(n),无论n多大,那么早晚都有结束的时候),这个在爬虫实战中的具体应用是:当每爬完一次,就自动进行下一次爬取,实现24小时不间断爬取。那么While如何能实现一直循环呢?
具体的方法其实很简单,那就用while True进行永久循环。
while True:
代码块
给大家截个图看下,下面这张图就是最终的代码效果,这个while True就是舆情监控系统实现24小时不间断爬取的秘诀,有个注意点,这个True得大写首字母,之后讲到的时候再详细介绍:
大家如果想停止while True的不停的循环,可以在点击右上角的红色终止按钮即可。我当初自己学的时候,写过这么两行代码:
while True:
print('hahaha')
大家可以自己试一下,效果也是挺鬼畜的,lol。
第四讲:Python函数与模块
说到函数,大家可能畏难情绪就上来了,也许可能就想到以前学的什么幂函数,指数函数各种看着很吓人的东西了,但其实在Python里提到的函数就跟你小学初中学的一元一次函数是一个难度级别的,基本上你能理解一元一次函数:y(x) = x + 1,你就能理解Python里的函数了。
- 函数的定义与调用
函数的一个最主要的功能就是让你可以不用一个代码重复写很多遍,
定义一个函数的格式如下,我们用def来定义函数,这个是一个固定写法,注意记得写冒号及代码前的缩进:
def 函数名(参数):
代码
我们以刚刚说的一元一次函数y = x + 1来演示下Python函数的写法:
def y(x):
print(x+1)
y(1)
这个其实和y(x) = x + 1基本就没什么太大差别了,前两行定义函数,第三行就是调用函数,调用函数其实很简单,只要输入函数名即可,如果含有参数,那么在函数名后面输入参数即可。这个第三行的y(1)就是表示y(1) = 1 + 1,根据第二行的内容,它将输出这个内容,最后输出:
2
其中第三行大家可以换成y(2),y(3)都可以,这样输出的结果就会随之改变.
比如:
def y(x):
print(x+1)
y(1) #第一次调用函数
y(2) #第二次调用函数
y(3) #第三次调用函数
那么输出的结果就是:
2
3
4
这边感慨一句,如下图,其实我们以前高中数学都学过f(x),这个f就是function(函数)的意思,以前没觉得它有多厉害,现在发现它和我们上面学的编程中的函数本质上其实是一个东西,或者说python中的函数,其灵感或者基石就是来自数学中的函数。如今学习编程,是重新体会了数学真的是很多学科基石呀。
有的时候函数括号里面不要参数也可以,这个大家简单了解即可,比如:
def y():
x = 1
print(x+1)
y() #调用函数
其中前三行定义了一个函数,第四行调用了这个函数,发现在这个函数里我们并没有输入参数,直接敲击y()就可以调用函数了,不过这样的话,就没有办法改变x的值,这个函数的输出结果只会是2:
2
这种不输入参数的函数定义方法,一般用的比较少,大家了解即可。
那么定义函数,在实战中有什么应用呢?比如说在舆情监控爬虫实战中就大有用途,我给大家演示下,大家先大概看下:
def baidu(company):
#这里是具体爬虫代码,第七章会讲
print(company + 'completed!')
companys = ['华能信托','阿里巴巴','百度集团','腾讯','京东','万科','华为集团']
for i in companys:
baidu(i)
上面这个代码就是舆情监控项目实战的一个基本框架了,其中第2行的具体代码,在第五章和第七章会讲给大家听。现在大家先关注这个函数,这个函数名叫做baidu(因为代码主要爬取的是百度新闻),参数为company,该参数在第2行的具体爬虫代码里和第3行的print(company + ‘completed!’)都有应用。其中这个company只是一个代号,你可以换成阿猫阿狗都可以,比如,你换成如下内容,只要下面的company也记得改了就行。
def baidu(cat):
#这里是具体爬虫代码,第七章会讲
print(cat + 'completed!')
第5行是个需要监控的公司列表,第6行for i in companys则是通过循环来对每个项目公司来进行监控。这边这个i你可以换成任何内容,没有影响的,比如你写成j,写成company都是可以的,因为它就是遍历列表,然后把列表元素输入到baidu(company)这个函数当中,也就是第7行的内容。
第7行就是把各个公司作为参数来运行baidu(company)这个函数。这样就实现了对各个公司进行舆情监控,我目前监控了200多家项目公司及信托公司,所以大家可以体会下函数的重要性,如果没有函数,也就意味着同样的代码我得复制200多遍。
- 函数参数、返回值与作用域
2.1 参数再研究
def baidu(company):
#这里是具体爬虫代码,第七章会讲
print(company + 'completed!')
companys = ['华能信托','阿里巴巴','百度','腾讯','京东','万科','建设银行']
for i in companys:
baidu(i)
我们再来把这几行代码研究下,初学者可能会有点疑惑,这个第一行的参数company是不是可以换成别的任何一个值,答案是可以的,这个company只是个参数,它就相当于y(x) = x + 1中的x,你换成可以用z来代替x,变成y(z) = z + 1,只是形式变了,对函数本身并没任何影响,只要x + 1中的x变成z即可。
所以我们完全也可以这么写,把company换成keyword,这个参数只是个代号而已。
def baidu(keyword):
#这里是具体爬虫代码,第七章会讲
print(keyword + 'completed!')
companys = ['华能信托','阿里巴巴','百度','腾讯','京东','万科','建设银行']
for i in companys:
baidu(i)
而最后两行中的i相当于y(1) = 1 +1 中的1,这个是函数调用输入的值。其中你可以把i换成j,换成k什么的都可以,因为无论换成什么,它都是表示这个列表companys中的每一个公司名称。
2.2 返回值
我们把最开始的代码稍微修改下,把print改成return,别的内容不变。
def y(x):
return(x+1)
y(1)
我们再次运行下,发现什么东西都没有,这是怎么回事呢,因为return和print函数不同,return相当于看不见的print,它是把原来该print的值赋值给了y(x)这个函数,学术点的说法就是该函数的返回值为:x+1。那么我们再稍稍修改下,就可以把y(x)显现出来了。
def y(x):
return(x+1)
a = y(1)
print(a)
上面提到其实y(1)已经是一个有数值的东西了,只是不会直观的让你看到,原来该print的y(1)现在就相当于在后台给y(1)一个数值,那么令它等于a,然后利用print就可以把它打印出来了。
可以看到,return和print还是很像的,只不过有的时候我们不希望把内容都print出来(那样最后代码输出显示的内容会过多)而是只是在需要的时候去使用它即可。
上面这4行代码就可以输出如下内容了:
2
同样在下面这个代码里,我们把print改成return,return就是返回值的一个函数,这个不会把keyword + ‘completed!’直接打印出来了,而是说把keyword + ‘completed!’赋值给baidu这个函数了。
def baidu(keyword):
#这里是具体爬虫代码,第七章会讲
return(keyword + 'completed!')
a = baidu('华能信托')
print(a)
这样输出的内容也同样还是
华能信托completed!
此外,return和print还有个不同的地方在于,return不用括号也是完全没有关系的,比如下面的代码是完全ok的,这个print是不可以的。
def baidu(keyword):
#这里是具体爬虫代码,第七章会讲
return keyword + 'completed!' #这里把括号去掉了
a = baidu('华能信托')
print(a)
去掉括号输出的内容也同样还是
华能信托completed!
可以看到return并不需要括号,当然你加上也没什么问题。
有的同学可能还有些疑惑,这个return感觉好像和print也没什么区别呀,反而还比print多绕了几步。那是因为这个代码还比较简单,所以两者的差异不大,如果原来print的是一堆内容,那return的左右就体现出来了。
当我们把一个公司相关的新闻标题,来源,评分都获取了之后,把它打印出来实在是有点有点繁琐,而你利用return则不用担心它把这些数据都打印出来了。而且你用return最大的好处是把函数得到的结果返回给了函数名,之后可以调用函数名就可以使用函数结果了,这个在高阶的应用里应用较多,这里了解即可。
2.3 变量作用域
这块内容其实不讲也没什么事,但就是怕有的初学者有疑问,再自己练习的时候不知道什么情况。简单提炼就是,你在函数内使用的变量是和函数外的程序没有关系的。
举个栗子:
x = 1
def y(x):
x = x + 1
print(x)
y(3)
print(x)
单纯看上面几行代码,大家想下最后会输出什么内容呢?
先给大家看下最后的输出结果,然后大家可以想一下:
4
1
同样是print(x),为什么打印出来的内容不一样呢?
如果你2.1参数再研究这一节你看明白了的话,那么这里大家就更容易理解了。其实函数y(x)里面的x和外面的x没有关系了,像之前讲过的,你可以把y(x)换成y(z),再把其他的x都换成z,那么这个函数其实是没有变化的:
x = 1
def y(z):
z = z + 1
print(z)
y(3)
print(x)
看上面的代码,大家应该会更加明白,这样输出的肯定就是4和1了,这个y(z)中的z或者说y(x)中的x只是在函数内部才有效,它不会影响外部的变量,函数的参数只是个代号,与外部的变量关系不大。
这个大家不太用深究,因为我们一般各个函数都是相互独立的,不太会产生什么干扰。
- 一些基本函数的介绍
这边给大家介绍下Python中常用的一些函数,其实之前在基础知识里都已经介绍了一些了,这边可以当做复习吧。
3.1 print函数
这个大家应该都非常熟悉了,这个只是拎出来再强调下这个函数的重要性,它在我们之后的编程中会经常用到,它第一个作用是用来打印输出结果,比如我一开始爬取阿里巴巴在百度新闻上的舆情(如下图),我得把最原始的爬取内容打印输出出来,然后寻找规律,获取我想要的内容,那么print的作用就很大了。
第二个功能在我这边是用来发现错误以及纠正错误,比如我不知道程序到底是哪里出了问题了,那么就在我觉得有问题的地方打印输出一下,看它打印输出的结果是不是我想要的,如果不是的话,再做修改。
3.2 str函数与int函数
这边在讲字符串的时候已经讲过str这个函数了,这个用的很多,因为我们有的时候经常要把字符串和数字拼接到一起,那么就需要用到str函数:
举个例子:
score = 85
print('A公司今日评分为' + str(score) + '分。')
我们将爬取到的分数已经获取了,想把它打印输出出来,那么涉及字符串的拼接就需要用到str函数,他可以把数字85变成字符串’85’。
int函数的话,其实用的不多,这边简单提下,比如下面这个score = ‘85’是一个字符串,按照下面这个写法就会报错,报错显示为数据格式不匹配:
score = '85'
if score > 80:
print('OK')
如果我们想把它与80进行比大小,就得用int函数把它转换成数字
score = '85'
score = int(score)
if score > 80:
print('OK')
这样就可以把字符串转换成数字,与数字进行比较了。
3.3 len函数
这个len函数最主要的作用是统计列表元素个数,当我们不知道列表一共有多少元素的时候,它能帮我们做一个统计,这个在之后的舆情监控之后又很大的作用。
举个例子,我爬取阿里巴巴,但不知道具体爬到了多少标题,那么用len就能获取标题个数,为之后的操作做准备:
title = ['标题1','标题2','标题3','标题4','标题5']
href = ['网址1','网址2','网址3','网址4','网址5']
for i in range(len(title)): #len(title)表示一个有多少个新闻,这里是5
href[i] = 'www.baidu.com/' + href[i] #这个其实就相当于 a = a + 1
print(str(i+1) + '.' + title[i]) #这个其实把字符串进行一个拼接
print(href[i])
还是拿我们之前第三讲:For语句详解讲过的一个例子来做示范,这个就是一个我们在舆情监控中经常用到的len函数。它主要针对我们不清楚有多少新闻个数的时候来进行应用,如果我们知道了一共就5条新闻,那么就不用写len(title)了,直接写for i in range(5)即可:
for i in range(5)
而实际爬虫过程中我们是不知道有多少新闻条数的,所以len函数的作用就发挥出来了,这边倒数第二行正好还讲到了刚刚讲过的str函数,大家也可以当做一个复习。
顺便提一句,len函数还可以统计字符串的长度,如下:
a = '123华小智abcd'
print(len(a))
最后输出结果为10,就是十个字符串。
3.4 replace函数
这个replace函数主要的作用是替换你想替换的内容,具体的使用方法如下:”字符串.replace(替换之前的内容,替换之后的内容)“,比如舆情监控的时候我们爬到的一条新闻标题是
a ='<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部'
a = a.replace('<em>','')
a = a.replace('</em>','')
print(a)
这样我们就能把新闻标题里我们不希望要的与给剔除掉,大家可以把这一块代码复制或敲到程序里运行看看,会得到如下结果:
阿里巴巴电商脱贫成“教材” 累计培训逾万名县域干部
在之后第六讲:正则表达式详解中,我会介绍另外一个替换的方法,那个方法更灵活,这边先埋个伏笔。
3.5 strip函数
strip函数主要的作用是删除空白符(包括’换行符\n’和空字符串’ ‘),具体的使用方法如下:”字符串.strip()“。
比如舆情监控的时候我们爬到的一条新闻标题是:‘ 华能信托2018年上半年行业综合排名位列第5 ‘,在这个标题前面后面都有些我们不想要的空白字符串,有的时候甚至还有讨厌的换行符,那么处理办法如下:
a =' 华能信托2018年上半年行业综合排名位列第5 '
a = a.strip()
print(a)
那么我们就可以获取到一条非常干净的新闻标题了。
华能信托2018年上半年行业综合排名位列第5
3.6 split函数
split函数主要的作用是根据你的想法来分割字符串,具体的使用方法如下:”字符串.split(‘分割的方法’)“。同样用实战中碰到情况来举例,如果我爬取到的日期是这样的内容:’2018年12月12日 08:07‘,我们是不想要最后的具体时分秒,我们只想要“2018年12月12日”,这里就没办法用replace办法,因为它可能是08:07,也有可能是09:20。但是我们知道‘2018年12月12日’和具体时分秒中间有个空格,那么我们就可以利用这个空格,把2018年12月12日和具体时分秒分割开来。这个分割的方法就是空格。
a = '2018年12月12日 08:07'
a = a.split(' ')[0]
print(a)
大家自己试一下,会得到如下输出结果:
2018年12月12日
这边有个小细节提醒下大家,这个split之后,不是分成几块了嘛,所以它的返回结果是一个列表,所以在第二行代码,如果我们想获取前半块内容,也是列表的第一个内容,就要输入序号0(在python中序号0表示第一个元素),要写成a = a.split(‘ ‘)[0]。
大家可以写这么几行代码来理解下我说的内容:
a = '2018年12月12日 08:07'
a = a.split(' ')
print(a)
我们可以看到输出的内容为:
['2018年12月12日', '08:07']
这样我们应该就更能理解split之后得到的其实是一个列表了,所以如果想获取列表的第一个元素,就要写list[0]来获取啦。
3.7 异常处理函数try except函数(这个其实叫try except语句,当初写的时候不够严谨,不过叫法并不影响使用)
这个异常处理函数也是一个比较有用的一个函数,也许你之前学习的过程中,经常程序会报错,然后程序就被迫中止了,那么利用异常处理函数的话,就可以避免程序因为哪一步程序出了错而整个程序终止,这在舆情监控的时候非常有用,因为它是24小时不间断运行的,如果哪里出了点小问题,比如爬取的某个网站突然崩溃了,但别的网站还ok,我们希望就不用管这个崩溃的网站,继续执行下面的代码即可。
异常处理函数的具体使用方法如下:
try:
主代码
except:
如果主代码出错了,那么该执行的代码
先举个简单的例子:
try:
print(1 + 'a')
except:
print('主代码运行失败')
根据我们已经学过的知识,print(1 + ‘a’) 这行代码肯定是会报错的,因为数字和字符串是不可以直接相加的,那么在这里我们用try except之后,try这一块失败了,程序没法运行,那么它就会跳转到except那里执行 print(‘主代码运行失败’),可以看到最后输出的内容为:
主代码运行失败
其实这个的逻辑有点像if else函数,try就相当于if,except就相当于else,两者的底层逻辑其实是一样的,都是一个不行,就执行另外一个。
那么这个在具体项目中的实践是怎么样的呢?
try:
#这里是百度新闻爬取的代码,之后第五第七章会讲
print('百度新闻爬取成功')
except:
print('百度新闻爬取失败')
如上面的代码,在第二行有具体的爬虫代码,如果它没出问题,那么就直接打印“百度新闻爬取成功”,如果它出问题了,那么就打印“百度新闻爬取失败”。
比如说如果我再print(百度新闻爬取成功)前面故意加一个错误的内容来做演示:
try:
#这里是百度新闻爬取的代码,之后第五第七章会讲
print(1 + '1')
print('百度新闻爬取成功')
except:
print('百度新闻爬取失败')
因为1 + ‘1’是两个不同类型变量相加,是没法执行的,那么它就会输出except里的内容,输出:百度新闻爬取失败。
这个当你爬取的网站多了之后就非常有用了,因为你不想因为百度新闻爬取失败,就耽误之后的新浪财经新闻的爬取,或者耽误微信推文的爬取。具体代码如下:
try:
#这里是百度新闻爬取的代码,之后第五第七章会讲
print(1 + 'a')
print('百度新闻爬取成功')
except:
print('百度新闻爬取失败')
try:
#这里是新浪财经新闻爬取的代码,之后爬虫进阶课会讲
print('新浪财经新闻爬取成功')
except:
print('新浪财经新闻爬取失败')
try:
#这里是微信推文爬取的代码,之后爬虫进阶课会讲
print('微信推文爬取成功')
except:
print('微信推文爬取失败')
可以看到,如上面的代码演示,每一个网站的爬取我都采用了try except函数来进行处理,这样无论是哪一个网站的爬取出现了问题(比如上面那个百度就会出问题,但是因为写了异常处理函数,所以会执行except里的内容,打印输出“百度新闻爬取失败”,而不会影响之后代码的执行),都不会影响别的网站的爬取工作,这样在进行24小时不间断爬取的过程中,我们就不用担心出现程序因为出错而自己中断的问题啦。
- Python模块/库介绍
模块(也有人把它叫作库)是Python这些年发展如此迅猛的一个原因,因为很多优秀的IT工程师在研发出非常棒的代码之后,愿意把它共享给大家进行使用,而储存这些非常棒的代码的地方就叫做模块,或者叫做库,有的库是python自带的,有的库则需要我们进行下载才可以使用。
引用库的方法一般如下:
import 库名
或者
from 库名 import 库里的一个功能
引用完库之后,我们就可以使用库里面的功能了。
我们先用一个简单的例子来演示库的使用,如果我们想让python来输出当前的时间,那么应用time库即可,这个是python自带的,不需要我们安装。
import time
print(time.strftime("%Y/%m/%d"))
这个就可以输出当天的时间了。
2018/12/11
或者从datetime这个库里面,引用datetime功能。前一个datetime表示库名,后一个datetime大家可以理解成功能,然后是用功能datetime的now函数获取时间。
from datetime import datetime
print(datetime.now())
这个输出的日期格式为:
2018-12-11 14:55:26.562000
其实这个也完全可以这么写:
import datetime
print(datetime.datetime.now())
这个效果和上面的代码是一样的,他也是调用datetime模块的datetime功能的now函数。这样大家就理解了,其实调用库只要学会import +库名就可以了,from 库名 import 功能只是为了之后调用的时候更简洁而已。
在项目实战中,比如在爬虫领域,我们经常需要用到的一个库叫做requests,它是我们能够通过python程序访问网站的基础,我们下面就带大家先来安装下这个库。
安装库有两个常用的办法:
1.Pycharm安装法
如果你使用的是Pycharm,直接在Pycharm中安装即可,具体安装步骤如下:
第一步,点击File,选择settings。
第二步:选择Project,选择Project Interpreter,选择右边的绿色的加号。
第三步:搜索你所需要的库的名字,比如这边的requests库,搜索完成后点击左下角的Install Package进行安装即可。
2.Pip安装法
如果你使用的不是pycharm编译器,比如说用的是Spyder,那么这里就可以用也很常见的 pip install 库名 安装办法,具体步骤如下:
第一步:同时按住Win + R键,调出运行框,输入cmd
第二步:在弹出的对话框里,输入 pip install requests,等待安装结束即可。
如果出现下图画面则说明安装成功了:
两种方法都可以,Pycharm法安装比较直观,但有的时候有的库你找不到那就用Pip安装法也很方便。
当我们把requests安装好了之后,让我们来小小实战一下吧,大家可以把这几行代码复制或者输入到程序中:
import requests
url = 'https://www.baidu.com/'
res = requests.get(url)
print(res.text)
第一步:首先通过import requests库把requests导入进来;
第二步:输入一个网址,这里我们用百度来做个示例,注意不要单纯的输入www.baidu.com,因为它完整的网址是https://www.baidu.com/,之后的第五讲我会解释下这一块,这一步大家先了解下即可;
第三步:通过requests的get功能来访问该网站;
第四步:把获取的网址内容打印输出出来,一个小注意点,这边要在res后加一个.text,因为这样才能输出文本。
这个是大家学习爬虫的第一步,大家看到这个爬取到的内容还是相当粗糙的,有很多值得改进的地方,但这些都不重要啦,我之后都会一步步讲到。我们要看到的是,通过这简单的4行代码,我们就能获取网页上面的信息,而之后爬取百度新闻,新浪财经,微信推文其实都是用的一模一样的原理,所以大家要有学爬虫不难的信心呀。
第五讲:综合实战1:爬虫初尝试 - 百度新闻爬取
下面我们就来进行舆情监控的项目实战 - 爬虫初尝试啦!有的人可能会怀疑,我学了上面的那些内容就可以进行舆情监控了?答案是利用上面所学,是完全可以的。Python其实不难,关键是教的人如何教,以及学的人如何学。
- 舆情监控基础-网络爬虫基本介绍
首先给大家讲解下爬虫的一些基本知识,我不会讲的太复杂,不会把网页的各种结构讲给你听,那其实一点必要都没有,你要做的事爬取信息,而不是搭建网站,所以大家跟我后面来学习如何获取信息即可。
我下面讲的都是实战中经常用到的,一些看上去很复杂其实没什么用的东西我通通不讲。
1.1 浏览器F12的运用,以及如何看网页源代码
网络爬虫,你首先得有一个浏览器,这里我强烈推荐谷歌浏览器(百度搜索谷歌浏览器,然后在官网https://www.google.cn/chrome/下载即可),很多国产浏览器的内核其实都是谷歌浏览器的技术。当然你用别的浏览器,比如火狐浏览器等都是可以的,只要它按F12(有的电脑要同时按住左下角的Fn键)能弹出如下图的内容即可,如果不行的话,那就自己下载一个谷歌或者火狐浏览器吧。
我们就以谷歌浏览器为例来演示下F12的强大作用,
我们百度搜索“阿里巴巴”,然后按一下F12(有的电脑还得同时按住Fn),弹出如下页面:
我们简单介绍下这个按住F12弹出来的东西,它叫做开发者工具,是爬虫工程师的利器,你不需要知道太多东西,你只需要会用下图的这三个按钮即可,你别看这个好像有点花里胡哨的,但是等会拨开现象看本质,你会发现内容其实很简单。
第一个按钮选择按钮,第二个
元素按钮,第三个
网络捕捉按钮,其实用的最多的还是前两个。我来一一做个介绍:
(1)选择按钮:
我们点击一下它,发现它变成蓝色了,然后你把鼠标在页面上移动移动,你会发现页面上的颜色机会发生改变,如下图:
与此同时,当你移动鼠标的时候,如下图,你会发现Elements里的内容就会随之发生变化,大家先不用管那些英文内容,目前你只需要知道下图红框里面的中文是我所需要的即可。
如果没看到中文,点击下下图那个箭头把内容展开即可
下面我们在选择按钮处于蓝色状态的时候,点击一下第一个标题,这时候选择按钮
再次变成灰色
,而Elements
里的内容也不再变动,此时我们可以关注下下图:
之前说过,我们只需要关心里面的中文即可,下面我们来解释下Elements的作用:
(2)元素按钮:
元素按钮里面的内容大家可以理解为它就是网站的源码,你最后爬虫爬到的内容大致就是长这个样子的。下面我们就要接着之前的操作来完成一些神奇的内容了:
在下图阿里那个地方鼠标双击俩下,这两个字变成可编辑的格式了!那就让我们来编辑下它吧!因为这个是流动广告,所以可能显示的是别的内容,比如你看到的可能是“找*_上阿里巴巴**”,大家依葫芦画瓢来改就成。
我们可以把它改成“男朋友”或“女朋友”,我们这边来改成“女朋友”先,然后同样双击下面一行的“baba上”使它变成可编辑的格式,把“baba上”中的baba删掉,如下图:
那么下面就是见证奇迹的时刻啦,我们可以看到第一个的标题变成下图了:
你还可以用同样的操作,先选择选择按钮,点击下面的阿里股价:
用同样的方法在Elements里对这个数字进行修改,可以改成任何你想改的数据,
比如改成:
说这么多,是想让大家对网络爬虫有个初步的概念,表达下F12是一个非常重要的功能,利用选择按钮和元素按钮
我们就可以获取我们想获取内容的在源码中的文本格式以及所在位置了。
(3)网络捕捉按钮:
这个其实在我的课程里用到的没有那么多,但在复杂爬虫项目中可能会有些应用,在基础课和进阶课大部分的时间里,你只需要理解选择按钮和元素按钮
即可。
我们这边来演示下网络捕捉按钮的用途:
切换到Network选项卡,随后重新刷新页面,可以发现这里多了很多内容,这些内容其实都是你看到的这个网址上的子网址。
比如这边我们把滚轴拖到最上面,然后选择第二个,点击它,发现右边会弹出一些框,选择Prewiew,我们可以看到它就是baidu的logo。
这边其实有的人用的会比较多,但我这边只是偶尔会用到,有一个简单的小知
识点,我们把滚轴滚到最上面,然后选择第一个,选择右边的Headers,然后一直往下拉,在Request Headers下面我们会看到有一行叫做User-Agent,大家先记住这个东西,不需要纠结这些都是什么东西,在下一小节的时候我们会用到,简单来说,它其实就是证明了你是在通过一个浏览器在访问这个网址,这是浏览器的一个代号,当你访问别的网站的时候这个User-Agent是不变的。
1.2 网址构成及http与https协议
这也是个小知识点,有的时候我们理解的网址是:www.baidu.com是大家最容易理解的网址,但其实这个在编程里或者它真实的名字其实是:https://www.baidu.com它前面有个“https://”这个叫做https协议,大家不用关注太多,只要知道一点,如果你在Python里输入[www.baidu.com](http://www.baidu.com) 它是不认识的,你得把“https://”加上才行,如下面所示。
import requests
url = 'https://www.baidu.com/'
res = requests.get(url)
print(res.text)
其实最简单的办法,就是你直接浏览器访问该网址,然后把链接复制下来就行。下面在实战中我们都如此来做。
1.3 查看网页源码的另外一个方式
除了F12,另外一个获取网页源码的方式是在网页上右击选择“查看网页源代码”,就可以获取这个网址的源代码,这个基本就是你python爬取到的最终信息。你用鼠标上下滚动下,就能看到很多内容,同样的,你不需要关心那些英文或者网页框架,你只需要知道你想获取的中文在哪里即可。
- 网页结构初步介绍
这块内容其实是后来补充的 ,因为之前觉得这块内容不讲也不影响之后的爬虫实战,后来想了想还是给大家补充下吧,虽然看网页源代码的时候,我们不怎么关心它的结构,我们只关心它里面的我们想爬的内容及其周边的一些文本,不过了解了网页结构的话,我们看网页源代码就没有那么感觉一头包的感觉了。
网页源代码像之前介绍的,就如下图所示:
初看很复杂,其实简单来说,网页结构很简单,就是一个大框套着一个小框,一个小框再套着一个小小框,一般文本内容都是在最后的小框里,如此反复而已,我们来看一下下面的这个截图就明白了,在网页源代码里这种层级关系通过缩进表现的很清晰。
其中,看到这样的箭头就表明它是个大框,里面还有小框,点开就可以看到里面的小框了,文本内容一般都是在最后的小框里。可以说这样网页结构就讲完了,如果你想自己写一个网页的话,那就是先写一个大框,再写一个小框,最后在小框里填上文本内容即可。
有的同学可能会有疑问了,既然内容都是写在小框里的,那为什么不直接写小框,而要在外面加一堆大框呢?这是因为同样是橘子,橘生淮南则为橘,橘生淮北则为枳,生于非洲就干瘪了,这个大框及中框就是用来作为定位你是什么样“橘”的定位词,比如同样叫作小王同学,东台中学3年级二班的小王同学和南通中学2年级三班的小王同学就是两个不同的同学,每个大框都有其独特的地方,使得里面的中框和小框都显得那么多独一无二。
比如这里的大框
对于爬虫来说,其实我们不需要了解这么多,只有当我们需要把数据可视化到网站上的时候,才需要具体学习这些大框,小框都是怎么写的。一般来说,这些大框,中框,小框都是用“<>”左右两个箭头包起来的,这个学术点的说法叫作节点,在每个节点里我们填写相应的内容即可。
在爬虫领域,我们一般只需要找到最后储存内容的小框,看看小框有没有什么特点,能够让我们把里面的内容提炼出来,如果小框不够用,比如都叫作二班(小框)的小王同学(内容),我们会再看看中框有没有什么特点,看看是2年级(中框)二班的小王同学还是3年级(中框)二班的小王同学。一般来说,用到中框就完全可以把我们想要的内容给定位出来了。
- 实战!百度新闻爬取
百度新闻是一个非常重要的数据源,这一小节就先来获取一下百度新闻的源代码。百度新闻的网址为:https://news.baidu.com/,如下图所示:
通过百度新闻搜索阿里巴巴,会跳转到如下图所示网页,发现其现在属于“资讯”版块,所以也可以直接在“资讯”里直接搜索百度新闻。
其网址为https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴。不过如果直接从网址上进行复制的话,其网址为:https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4,它最后并不是“阿里巴巴”四个字,而是一些字母数字加百分号的内容。因为网页识别的是英文字符,中文需要转码才可以识别,而这个字母加百分号的内容可以看作“阿里巴巴”四个字在网页上的“英文”翻译。对于百度新闻,两种网址都可以直接用。
3.1 获取网页源代码
通过第一章最后介绍的requests库来尝试获取下百度新闻的网页源代码,代码如下:
import requests
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴'
res = requests.get(url).text
print(res)
获取到的源代码如下图所示:
可以看到其并没有获取到真正的网页源代码,这是因为这里的百度资讯网站只认可浏览器发送过去的访问,而不认可直接通过Python发送过去的访问请求,那么该如何解决该问题呢?这时就需要设置下requests.get()中的headers参数,用来模拟浏览器进行访问。
Headers参数记录的其实就是网站访问者的信息,headers中的User-agent(中文叫作用户代理)就是反映是用什么浏览器登录的,其设置方式如下所示,User-agent的获取稍后会讲。
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
设置完headers之后,在通过requests.get()请求的时候需要加上headers信息,这样就能模拟是通过一个浏览器在访问网站了,代码如下:
res = requests.get(url, headers=headers).text
完整代码如下所示:
import requests
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴'
res = requests.get(url, headers=headers).text
print(res)
运行结果如下图所示,可以发现此时已经获取到网页的源代码了。
这里的headers是一个字典,它的键名为:’User-Agent’,它的值为:’Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36’,User-Agent其实就是代表这个访问的浏览器是哪家的浏览器。
上面代码用的便是谷歌(Chrome)浏览器的User-Agent,这里以谷歌浏览器为例讲解下如何获取浏览器的User-Agent。首先打开谷歌浏览器在搜索框输入:about:version(注意是英文格式的冒号),然后在弹出的界面中找到用户代理,它里面就是User-Agent。
对于实战,只要记得在代码的最前面,写上如下代码:
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
然后每次用requests.get访问的时候,加上headers = headers即可。
res = requests.get(url, headers=headers).text
有时不加headers也能获得网页的源代码,比如第一章最后通过requests库爬取Python官网就不需要加headers。不过headers只要在开头设置一次,之后直接在requests.get()中添加headers=headers即可,所以并不麻烦,而且可以避免可能会出现的爬取失败。
这里可以看到通过短短4、5行代码,我们就能够获得网页的源代码了,而这个可以说是网络数据挖掘中最重要的一步了,之后所需要做的工具就是信息提取和分析了。
3.2 分析网页源代码信息
获取到网页源代码后,我们想提炼其中的新闻标题、网址、日期和来源等信息。在提炼这些信息之前,我们有三种常见的分析方法来观察这些信息的特征。
(1) 方法1:F12方法
点击选择按钮,选择一个标题,可以在Elements中看到,我们所需要的标题内容就在这一片内容中,用同样的的方法可以查看新闻日期和来源等信息。
如果看不到其中的中文信息,那是因为它被折叠了,点击折叠箭头展开折叠就可以看到中文了。不过有时通过F12看到的源代码并不一定准确,所以也常常和下面两种方法一起使用。
(2) 方法2:右击选择“查看网页源代码”
和之前提到过的一样,我们在浏览器上右击,选择“查看网页源代码”,到了源代码网页的时候,可能得往下滚动一下滚轮才能看到内容,然后便可以通过Ctrl + F快捷键(快速搜索快捷键)定位关心的内容了。
(3) 方法3:在Python获得的网页源代码中查看
在获取到源代码的输出框内通过Ctrl + F组合键,调出搜索框,搜索所关心的信息,这种方法也比较常见,不过需要先通过程序获得网页源代码信息。
在源代码里可以看到,关于新闻的标题,来源日期以及正文其实都已经有了,只不过被一些英文、空格以及换行包围着,需要通过一个手段将这些信息提取出来。一个常见的提取信息的手段就是通过正则表达式来进行提取,将在下一小节进行详细讲解。
第六讲:爬虫进阶基础:正则表达式详解
当初我自己学的时候,看到正则表达式几个字时候,畏难情绪就上来了,感觉好像很难很高大上的东西,但后来实战之后发现其实很简单,用的格式都是一样的,只是初学的时候,因为第一次接触,可能会有点不太好理解,当你实际用过两次,你就会发现它其实很简单,就是个提取信息的手段罢了。
- 正则表达式基础1 - findall方法
首先我们拿一个简单的例子来演示下正则表达式的作用,比如说我想提取’Hello 123 world’中的3个数字:
import re
content = 'Hello 123 world'
result = re.findall('\d\d\d',content)
print(result)
我们同样用大白话来解释下每一行:
引入正则表达式库,它也是个模块,需要用import引入
有一个文本内容叫作:content = 'Hello 123 world'
使用正则表达式中的findall方法来寻找3个数字,将结果赋值给result变量
打印result变量
其中re这个库是python自带的,所以不用额外安装。我们来看下返回的结果,这边埋个伏笔:大家关注下这个返回的结果是什么类型:
['123']
插句题外话,其实很少有讲课的直接把findall方法放在最开始讲,传统讲课会先讲match方法,search方法等匹配方法,我当初也是这么学的,后来实战的时候发现findall方法是一招鲜吃遍天,根本不需要掌握其他的花里胡哨的东西,大家跟我把findall方法掌握好了,正则表达式就基本掌握一半了。
我们首先来解释下findall方法的使用规则,因为findall很重要,我就自己做了个图(见下图),简单来说,它是根据匹配规则在原始文本中找寻合适的内容:
我们再来提一下这个匹配规则:‘\d’表示匹配一个数字,‘\d\d\d’就表示匹配三个数字,所以re.findall(‘\d\d\d’, content)就是在content中寻找连续的三个数字。
有一个非常重要的注意点,findall最后得到的其实是一个列表,这个是刚刚留下的伏笔:[‘123’]最后得到的其实个列表,而不是字符串或者数字,这个很多初学者经常会忽略这一点,我们下面再做一个演示大家就更加明白了。
下面这个例子目的是我们要找到字符串里所有的3位数字:
import re
content = 'Hello 123 world 456 华小智python基础教学135'
result = re.findall('\d\d\d',content)
print(result)
大家可以把代码复制或者敲入程序里跑一下,输出的结果为:
['123', '456', '135']
可以看到,findall最后得到其实是一个列表,如果我们想获取列表中的某个元素,那么就需要使用之前第二章讲列表时使用的list[i]的方法:
a1 = result[0] #注意列表的一个元素的序号是0
print(a1)
a2 = result[1]
print(a2)
a3 = result[2]
print(a3)
输出内容为:
123
456
135
另外一个逐行打印这个findall爬到的所有内容的手段是:
for i in result:
print(i)
同样可以看到输出结果:
123
456
135
有个小注意点,这些虽然看着是数字,但是它却是从一个字符串里提取出来的,所以它其实是3个字符串,而不是数字,这个在列表里我们也可以看出来:
['123', '456', '135']
或者我们用type函数来显示数据类型:
a = type(result[0])
print(a)
输出结果可以看到,这里的’123’其实不是数字,而是字符串:
<class 'str'>
有的同学可能这个时候要问了,如果我不仅仅是想匹配数字呢,比如我想匹配文字,以及一些空格或者换行该怎么办呢?那就需要用到下一小节的知识点了。
- 正则表达式基础2- 非贪婪匹配(.*?)
那么我们下面来介绍下常用的匹配规则的符号:
模式 | 描述 |
---|---|
\d | 匹配一个数字字符 |
\w | 匹配一个字母、数字及下划线字符 |
\s | 匹配一个空白字符 |
\S | 匹配一个非空白字符 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
. | 匹配一个任意的字符,换行符除外 |
* | 匹配前面的字符无限次直到停止 |
? | 常和.与配合使用,组成*非贪婪匹配 |
() | 匹配括号内的表达式,也表示一个组 |
大家看到这么多是不是感觉有些头晕,头晕正常,我刚学的时候也这样,那时候学的符号更多,现在上面你看到的已经是我精简一半的内容了。不过有个好消息是,在实战中,你90%情况下需要用到的可能只有这两种情况:(.?)与.?,大家先不用管这个是什么,我们待会就讲,我先讲一下上面是换行符\n和制表符\t:
"\n"表示输出一个换行符,相当于你在编辑WORD时用到的Enter键
"\t"表示后退一个制表符,相当于按一下Tab键或者是按八下空格键
说白了,\n表示换行,\t就是八个空格键,\n偶尔会用到,\t基本用不到,这边仅仅是科普下制表符是什么。在下面这个图里我们可以看到,在红框标题后面其实就是个换行符,因为它下面就换行了。
下面这个知识点就异常重要了,它可以说是正则表达式的核心内容了:
- 非贪婪匹配(.?)与.?
大家可能会有点好奇它为什么叫做非贪婪匹配,这个不用管它,因为有个匹配方式叫做贪婪匹配.*,当初我花了挺多时间研究,最后实战完发现贪婪匹配几乎毫无作用,单纯学非贪婪匹配已经完全足够,既然不学贪婪匹配,那就没有必要了解它为什么叫非贪婪匹配了,大家只要知道怎么用即可。
先聊下(.?),然后我们再聊下.?,俩者意思差不多,只不多作用稍有不同。
简单来说(.?)的作用就是来找到你想要的东西,同时你不确定它的长度以及格式,但是你知道它大概在哪两块内容中间**。这个很重要,所以我们同样画个图来理解一下。
如上图所示,(.*?)就是用来获取文本A与文本B之间的内容,我们并不需要知道这个内容到底有多长以及它里面是否有什么乱七八糟的字符。
首先拿一个简单案例做演示,其目的是提取文本A和文本B之间的新闻来源,主要用到的就是上一小节提到的findall方法和这一小节的非贪婪匹配,代码如下:
import re
res = '文本A百度新闻文本B'
source = re.findall('文本A(.*?)文本B', res)
print(source)
运行结果如下,注意这里返回的是一个列表。
['百度新闻']
在实战中,我们一般不把匹配规则直接写到findall后面的括号里,而是如下拆成两行来写,先写匹配规则,在写findall语句。因为有的时候匹配规则会比较长,分开写会比较清晰。
p_source = '文本A(.*?)文本B'
source = re.findall(p_source, res)
实战中,满足符合**文本A(.?)文本B的匹配规则内容通常不止一个,演示代码如下:
import re
res = '文本A百度新闻文本B,新闻标题文本A新浪财经文本B,文本A搜狐新闻文本B新闻网址'
p_source = '文本A(.*?)文本B'
source = re.findall(p_source, res)
print(source)
运行结果如下,获得的是所有符合符合**文本A(.?)文本B的匹配规则的内容列表了。
['百度新闻', '新浪财经', '搜狐新闻']
然后直接拿实战来展示一个示例,如下图所示,我们想提取其中新闻来源及日期信息。
利用非贪婪匹配提取信息最重要的一点就是寻找到定位所需内容的文本A和文本B。在这里可以看到新闻来源和日期都在一个
的框里,之前在2.2小节讲网络结构的时候也提到过,class表示类别,同一类别的框里存储的是类似的内容,那么利用
和
import re
res = '<p class="c-author"><img***>央视网新闻 2019年04月13日 13:33</p>'
p_info = '<p class="c-author">(.*?)</p>'
info = re.findall(p_info, res)
print(info)
这里作为演示,把所有内容都写到一行里了,实战中其实是有换行的,关于换行的处理将在之后便讲解。运行结果如下:
['<img***>央视网新闻 2019年04月13日 13:33']
其中提取的内容中有一些我们不需要的内容,比如图片标签,以及 这个我们不需要的字符串,这些文本清洗的方法将在之后讲解。
3.正则表达式基础3 - 非贪婪匹配.*?
如果说(.?)是用来获取文本A与文本B之间的内容,那.?是用来做什么的呢?为了和之前(.?)中提到过的文本A和文本B不混淆,下面我用文本C和文本D来做展示,它的作用简单来说是表示文本C和文本D之间的内容,因为我们不想写太多的东西或者说*文本C和文本D中间的内容其实是经常变动的,我们同样用一张图来演示一下:
我们再以一个实战的例子来做个演示,很多时候新闻标题和新闻链接靠的非常近,下图我们可以看到这个新闻链接和新闻标题其实都是在
这个框框内。我们这边再补充下网页源码结构的知识点,
其实是网页源码中的一个“块”,根据缩进,我们可以判断里面的内容其实都从属于这个块下面。这个大家如果不理解也没有关系,大家只要知道在寻找新闻链接和新闻标题的时候我们会用到来作为上面那张图的文本C即可,这边因为下图只是网页源码的一小部分,大家可能还不太理解为什么要选取来作为定位的文本,大家可能会问为什么不选_呢,这个是因为它作为定位条件强度不够,这个暂时先不用在意,我下一章节讲爬取百度新闻实战的时候详细讲解。
这边我们同样先不考虑换行的问题,把它写到一行里面给大家先做个如何获取新闻标题的示范:
import re
res = '<h3 class="c-title"><a href="http://news.hexun.com/2018-12-12/195521925.html" data-click="{一堆英文}"><em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部</a>'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
title = re.findall(p_title, res)
print(title)
大家可以把这一段代码复制到程序里跑一下试试看,会得到如下的结果:
['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
其实我们这边的重点就是如何写出下面这行代码,之后的findall处理方法我相信大家已经很熟悉了:
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
我们来分析下面这块图,可以看到下图画红框的两个地方,是我用来定位标题的
我同样画了个图来方便大家理解:
蓝色字体的部分,我们可以理解为之前说过的文本A和文本B,它们的作用就是为了帮我们定位到我们关心的内容:新闻标题。而中间这个绿色的字的话,我们可以看到上面的图,在
和>之间有一堆英文字母,其实那些内容是我们不关心的,但是在写匹配规则的时候,又不能当它们不存在,所以这里我们就用到了.?,如果说(.?)是为了获取,那么**.?的作用就是为了填充,他就是用来代替和>之间我们所不关心的内容的。
我们刚刚演示的时候,都没有考虑换行的情况,但实际下面这个图里的源码是存在很多换行的,**而.?是没有办法捕捉到换行的,如果遇到换行的时候它就不会继续匹配换行之后的内容了。
那么如果有换行应该如何处理呢,那就要用到下面一个知识点,修饰符的内容了。
- 修饰符介绍
修饰符有很多,我这边只给你介绍一个,因为我做了很多爬虫项目,用到的只有这么一个,别的都是花里胡哨基本不需要用到。
这个修饰符就是re.S,它唯一的作用,就是在findall查找的时候,可以自动考虑到换行。不用管它为什么叫修饰符了,大家知道他能自动考虑网页源代码换行即可。
它的使用方法如下:
下面这个完全就是实战的代码了:
import re
res = '''<h3 class="c-title">
<a href="http://news.sina.com.cn/o/2018-12-12/doc-ihqackaa4351174.shtml"
data-click="{
'f0':'77A717EA',
'f1':'9F63F1E4',
'f2':'4CA6DD6E',
'f3':'54E5343F',
't':'1544622684'
}"
target="_blank"
>
<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部
</a>
'''
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
href = re.findall(p_href, res,re.S)
title = re.findall(p_title, res,re.S)
print(href)
print(title)
大家可以复制到python里跑一遍试试看,会得到如下的结果:
['http://news.hexun.com/2018-12-12/195521925.html']
['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
前面十多行代码看着唬人,其实就是把网站源码复制过来了而已,里面包含了网址源码自带的换行符,我们用‘’’内容’’’的格式来把这些内容框起来,之前讲过‘’’内容’’’的作用一般是用来写注释,不过这里也可以用来把带换行的文本框起来。
我们重点看下这4行代码:
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
href = re.findall(p_href, res,re.S)
title = re.findall(p_title, res,re.S)
同样用一张图来解释下第一行代码:
第一行phref代码在
后面我加了一个**.?_,这个是因为这边源码已经考虑换行了,所以在后面其实是有换行符和几个空格的,那么我们就像之前讲过的那样要用.?
**来把这些我们并不关心的换行符和空格给填充了。
第二行代码没有任何变化,第三和第四行代码,我们都在res后面加了一个,re.S,这个就是为了利用re.S换行修饰符,这样我们就不用考虑源代码里有换行的问题了。
这个在某些网站的时候特别有用,比如在爬百度新闻的时候你就需要用到这个,当然很多网站比较简单,你都不需要考虑换行的问题。
- sub()方法
讲到这里,我们已经可以说基本上正则表达式已经讲完了,用上面的知识你基本上就可以分析80%以上的网页源代码内容了。这边在补充一个sub()方法,它是英文substitute(替换)的缩写,它的具体使用格式是:re.sub(需要替换的内容,替换值,原字符串), 主要就是用来处理正则表达式获取到的内容,比如说,我们之前获取的到的新闻标题,其实有点瑕疵:
['http://news.hexun.com/2018-12-12/195521925.html']
['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
它中间的和并不是我们想要的东西,那么如何能把它替换掉呢,其实传统的有一种方法是使用我们之前提过的replace函数,但是replace函数你得提前知道你需要替换的内容,比如说我们先用传统的replace函数来替换,注意下面的这个title它是个列表,虽然它这里只有一个元素,但也要用title[0]才能调用它:
title = ['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
title[0] = title[0].replace('<em>','')
title[0] = title[0].replace('</em>','')
print(title[0])
它可以获取如下结果
阿里巴巴电商脱贫成“教材” 累计培训逾万名县域干部
但是这个replace方法其实不够灵活,如果在别的标题里,<>里不是em,而是fm,那么你又得写一个新的replace语句。而sub()方法则比较好的解决了这个问题,使用格式为:re.sub(需要替换的内容,替换值,原字符串),代码如下:
title = ['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
title[0] = re.sub('<.*?>', '', title[0])
print(title[0])
同样可以得到:
阿里巴巴电商脱贫成“教材” 累计培训逾万名县域干部
我们来解释下这个代码:title[0] = re.sub(‘<.?>’, ‘’, title[0])。看着下面的图,我们来理解下,我觉得大家应该能理解,我就不多讲了,其中<.?>大家可能觉得有点不太容易理解,其实回顾下我们之前讲过的.?:用来表示文本A和文本B中间的所有内容,它其实就是表示任何<>形式的内容,无论<>里面填写的时候,都算是<.?>,那么它自然也包括和了。
我初学爬虫的时候,是用下面的方法来使用sub函数的,明明写一行就可以解决的事情,当初非写了两行,现在想来,稍微低效了点。当然了,你像我当初那么写也是完全没有问题的,只不过如果出现新的类似的东西,你又得重新加一行了。
title = ['<em>阿里巴巴</em>电商脱贫成“教材” 累计培训逾万名县域干部']
title[0] = re.sub('<em>', '', title[0])
title[0] = re.sub('</em>', '', title[0])
print(title[0])
- 中括号[ ]的用法(理解既可,不必深究)
本来不想介绍这一个内容的,因为其实用到的情况不多,但是如果真的碰到了类似的情况,不会使用正则表达式的中括号可能还是稍稍有点麻烦。中括号主要有两个功能:
1.最主要的功能:在中括号里的内容不再有特殊含义
我们之前了解过,在正则表达式里,像.,,?都有其特殊的含义,但是如果我想找的就是这几个符号该怎么办呢?比如说我想把一个字符串里所有的号都换成空值,其实这个在爬股票的时候是有用的,因为有的上市公司名称里有*号,我们需要把它替换掉:
company = '*华能信托'
company1 = re.sub('[*]','',company)
print(company1)
最后输出结果:
华能信托
2.表示某几个的范围,比如我要把爬到的日期里的“年月日”通通都换成“-”号,那么通过下面的方法就可以做到。
date = '2018年12月12日'
date = re.sub('[年月日]', '-', date)
date = date[:-1]
print(date)
补充一个知识点,date = date[:-1]其实是一个字符串的切片,这个的含义就是取该字符串除了最后一个元素的其他元素,因为如果你不写这么一行,那么你获得的内容是:2018-12-12-,最后的‘日’也给替换成‘-’号了,所以得用date = date[:-1]方法把这个‘-’号给去掉,这边了解即可,因为除了这儿别的地方基本也没用到。
这个其实你也可以这么写:
date = '2018年12月12日'
date = re.sub('年', '-', date)
date = re.sub('月', '-', date)
date = re.sub('日', '', date)
print(date)
其实这样写可能大家更好理解一些,不过就是稍稍不那么简洁罢了。
学完正则表达式就能进行比较高阶的操作了,之前我们已经可以把百度新闻的网页源码给获取下来,可以说百度新闻的数据挖掘,还差一个信息提取和文本分析的工作就完成了,那么下面就让我们利用正则表达式来把这最后的临门一脚给踢完吧。
在之前已经实现了百度新闻网页源代码的获取,下面就来通过正则表达式来提取百度新闻标题、网址、日期及来源等信息。
1.1 获取网页源代码
首先回顾一下之前获得网页源代码的代码:
import requests
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴'
res = requests.get(url, headers=headers).text
print(res)
通过上面代码就可以获取阿里巴巴在百度新闻上的源代码了。
1.2 编写正则表达式提炼相关新闻信息
(1) 获取新闻的来源和日期
在之前提过,通过观察网页源代码,发现每个新闻的来源和发布日期都是夹在
和
和
来作为文本A和文本B来获取中间的来源和日期信息。
import re
p_info = '<p class="c-author">(.*?)</p>'
info = re.findall(p_info, res, re.S)
print(info)
这边写re.findall的时候要注意re.S的使用,使用了re.S之后,它会自动考虑换行,因为在源代码里这些代码是存在换行的,(.?)无法匹配换行,如果不写re.S的话会获取不到内容。其中这个info是一个存储re.findall得到的列表,也可以换成别的名字,这边用info的原因是因为它是information(信息)的缩写。
最后输出的内容如下:
可以看到它的确得到了新闻来源以及发布日期,不过此时新闻来源和新闻日期是混杂在一起的,我们希望能将它们分割开来,以及这个获取的结果里有很多<img**>标签、空格、换行符\n和制表符\t(制表符就是按一下Tab键产生的8个空格),所以这个得到的数据还需要进行二次提炼,这个过程叫作数据清洗,我们等会讲,这里先来讲如何获取新闻标题和网址。
(2) 获取新闻的网址和标题
获取了来源和日期,便来研究下如何获取新闻网址和新闻标题吧,这个在之前讲正则表达式的时候已经讲过了,这里当复习并补充些新内容。先看新闻网址的提取规律:
除了在源代码里寻找规律,还可以通过F12取不同的新闻来看看,如下图所示,新闻网址前面都是有写,其实这个title就是标题的意思,而且class表示类别,所以猜测之后用正则表达式来选择文本A(.?)文本B来定位新闻网址的时候很有可能就会用到它。
除了在源代码里验证,还有一种方法来验证下的确是用来定位新闻网址的利器,在网站上右击,选择“查看网站源代码”,在源代码页,搜索class=”c-title”,如下图所示,可以看到它正好搜到了10条内容,这个与百度新闻一页的新闻个数是一样的,那么可以肯定的是:用是一定可以定位到新闻链接和新闻标题的。
下面我们就来看具体代码:
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
href = re.findall(p_href, res, re.S)
和之前提到过的一样,在用来定位的文本A中,用.*?代替不关心的内容,在文本B中,用网页源代码中的双引号作为定位条件,算是个小技巧。
标题的正则表达式编写在正则表达式的时候也讲过了,代码如下:
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
title = re.findall(p_title, res, re.S)
简单复习一下ptitle是怎么写出来的,如下图所示,其中**.?其就是代表从到下一个>号之间我们所不关心的内容,里面含有新闻的网址还有别的一些内容。然后在>号之后就是新闻的标题内容了,利用(.?)来获取该内容。最后用来定位的文本B**,选择的是,因为观察网页源代码,发现标题最后都会有这个作作为收尾。
通过print(href)和print(title)将两个列表打印输出,输出的内容如下:
可以看到网址链接基本没有问题,而标题里面的数据并不完善,其中每个标题开头结尾含有\n换行符和一些空格,新闻标题中间则含有一些和等无效字符,那么这时候就要把数据进行一下清洗,如何清洗我们在下一小节进行分析。
1.3 数据清洗并打印输出
这一小节的内容比较重要,因为之后很多数据清洗的手段都是基于这节讲到的一些处理手段。上一小节讲过除了新闻链接没什么问题外,获取到的新闻标题、日期和来源的数据其实都并不完善,首先来清洗新闻标题,这个相对容易一些。
(1) 清理新闻标题
新闻标题的主要问题是两个,一个是每个标题开头结尾含有\n换行符和一些空格;另一个是中间则含有一些和_等无效字符。首先用字符串.strip()函数的方法把不需要的空格和换行符去掉,代码如下:
for i in range(len(title)):
title[i] = title[i].strip()
接下来再用上一章讲正则表达式时讲过的sub方法来把和处理掉,它的使用格式为:re.sub(需要替换的内容,替换值,原字符串):
for i in range(len(title)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>','',title[i])
我们知道这样.?可以代替文本A和文本B之间的所有内容,所以<.?>表示了形式为是<任意文本>的内容,这样我们就可以把和处理掉了。
(2) 清理新闻来源和发布日期
现在来清理下新闻来源和发布日期,在3.1.2小节也提到过,获取到info列表里的主要问题为:1.夹杂着很多等的图片标签信息,需要将其清除掉;2.来源和日期都在一起了,需要把它分开;3.来源和日期的首尾都有一些空格和换行符等内容,需要把它们清理掉。
首先通过解决第一个问题,通过如下代码即可清洗类型的图片标签信息:
info[i] = re.sub('<.*?>', '', info[i])
然后解决第二个问题:这个新闻来源和发布日期都被储存在info这个列表里的每一个元素里了,需要用Python基础1.4.3小节里讲过的字符串.split(‘分割符’)方法来进行分割。
这边的info列表中的每个元素,我们可以观察一下,如下图所示:
可以发现来源和日期都通过下面这个字符串分割开来了:
那么就可以通过split()函数来进行来源和日期的分割了,代码如下:
info[i].split(' ')
注意通过split()函数分割后得到的是一个列表,之后需要通过列表选取元素的方式来分别获取具体的日期和来源。
针对第三个问题,通过strip()函数可以去除多余的空格和换行符:
source[i] = source[i].strip()
date[i] = date[i].strip()
对新闻来源和日期清洗优化的完整代码如下:
source = [] # 先创建两个空列表来储存等会分割后的来源和日期
date = []
for i in range(len(info)):
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
这里通过列表.append(新元素)的方法来把分割后的来源和日期进行整理。具体来说,先创建两个空列表来为之后的储存做准备,然后用source.append(来源)和date.append(日期)的方法来给两个空列表添加新元素(新的来源和日期)。如下图所示,来源和日期都被较好的提炼了。
所有代码汇总如下:
import requests
import re
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴'
res = requests.get(url, headers=headers).text
# 正则提取
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
p_info = '<p class="c-author">(.*?)</p>'
href = re.findall(p_href, res, re.S)
title = re.findall(p_title, res, re.S)
info = re.findall(p_info, res, re.S)
# 数据清洗及打印输出
source = []
date = []
for i in range(len(title)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
print(str(i+1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')')
print(href[i])
其中倒数第二行有个注意点,因为i是数字,所以字符串拼接的时候要用str函数转换一下,并且i是从0开始的序号,所以要写str(i+1)。
运行结果如下图所示,所需要的信息基本都获取到了。
2.1 批量爬取多个公司的百度新闻
成功爬取了阿里巴巴的新闻舆情的标题,链接,日期和来源后,那么如果换一家公司来做数据挖掘的话该怎么办呢?最简单的办法就是把原来的代码复制一遍,然后改一下url即可,但是如果有几十个公司需要爬取呢?如果都是用复制的方法来做的话就有点低效了,那这时候就需要利用函数的知识点来解决批量爬取的问题。
首先我们先用一个简单的例子来带大家回顾下函数的一些基本知识:
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company
print(url)
# 批量调用函数
companys = ['华能信托','阿里巴巴','百度集团']
for i in companys:
baidu(i)
首先定义了一个名字叫作baidu的函数,这个函数内容其实只有两行代码,第一行创建一个url变量,其中company是函数参数,第二行就是把这个url打印输出出来。函数定义完了之后,通过for循环便可以批量的调用baidu()这个函数了。
输出结果如下:
https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=华能信托
https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴
https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=百度集团
这个其实就是之后要讲到的批量爬取的核心内容了,下面的代码主要就是改了这个url就能够实现多个公司的批量爬取了。代码如下:
# 引入库和headers相关代码
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company
res = requests.get(url, headers=headers).text
# 1节讲过的数据提炼、清洗等相关代码,注意缩进,写到函数里面来
companys = ['华能信托','阿里巴巴','万科集团','百度集团','腾讯','京东']
for i in companys:
baidu(i)
print(i + '百度新闻爬取成功')
这个代码主要改的内容主要就是定义了一个baidu函数,然后修改了url那块。最后通过for语句,来调用baidu(company)这个函数。
完整代码如下:
import requests
import re
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company # 把链接中rtt参数换成4即是按时间排序,默认为1按焦点排序
res = requests.get(url, headers=headers).text
# print(res)
p_info = '<p class="c-author">(.*?)</p>'
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
info = re.findall(p_info, res, re.S)
href = re.findall(p_href, res, re.S)
title = re.findall(p_title, res, re.S)
source = [] # 先创建两个空列表来储存等会分割后的来源和日期
date = []
for i in range(len(info)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
print(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')')
print(href[i])
companys = ['华能信托', '阿里巴巴', '万科集团', '百度集团', '腾讯', '京东']
for i in companys: # 这个i只是个代号,可以换成其他内容
baidu(i)
print(i + '百度新闻爬取成功')
2.2 自动生成txt报告
我们已经能够批量爬取新闻了,也可以在Python中生成舆情结果了,如果还想把这些内容导出来该怎么办呢,一个最简单的办法就是复制粘贴到txt或者word文件当中,不过这个方法比较低效。在Python中,其实是可以自动生成txt报告的。下面就来详细介绍下,如何把之前提炼之后的内容自动以txt格式导出来。
首先来讲一下如何生成一个一个txt文件,格式如下:
file1 = open('E:\\测试.txt', 'a')
file1.write('把内容输入到txt中,就是这么简单')
file1.close()
试着运行下上面的代码,会发现在E盘中多出一个叫作测试.txt的文件夹。
用一张图来解释一下:
按照如下格式就能打开(如果不存在,就新建一个)一个txt文件:
变量名 = open('文件路径','写入方式')
其中文件路径,就是文件所在的地址,如果没有该文件就自动新建一个txt文件;写入方式主要有两种,如下表:
写入方式含义w每次写入数据的时候,都会把原来的数据清除a不清除原来数据,在原数据之后写入新内容 | | | | :—-: | :—-: | | | | | | |
这边一般用写入方式’a’,因为这样不用担心原来的内容被清空。
下面一个知识点,file.wirte就是通过write方法把内容写入到txt文件中,这边可以把write括号中的内容换成别的内容看看。
最后一个知识点,创建完txt文件后,我们通过file1.close()的方法将文件关闭。
此外,如果出现乱码现象,可以在open()函数中增加encoding参数,代码如下:
变量名 = open('文件路径','写入方式',encoding='utf-8')
掌握了如何创建txt文件以及如何写入内容之后,就可以来进行数据挖掘的自动生成报告实战了,代码如下:
# 引入库和headers相关代码
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company
res = requests.get(url, headers=headers).text
# 1节讲过的数据提炼、清洗等相关代码,注意缩进,写到函数里面来
file1 = open('E:\\数据挖掘报告.txt', 'a')
file1.write(company + '数据挖掘completed!' + '\n' + '\n')
for i in range(len(title)):
file1.write(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')' + '\n')
file1.write(href[i] + '\n') # '\n'表示换行
file1.write('————————————————————————————' + '\n' + '\n') # 分隔符
file1.close()
companys = ['华能信托', '阿里巴巴', '万科集团', '百度集团', '腾讯集团']
for i in companys:
baidu(i)
print(i + '百度新闻爬取成功')
大家看看自己的E盘文件夹里,是不是多了一个叫作数据挖掘报告的txt文件呢。
其中‘\n’表示换行符,之前讲正则表达式的时候简单提到过,主要就是做一个换行的作用,让排版更加好看,可以把它当做字符串来一起拼接。其他内容其实和之前讲的打印输出数据清洗后的数据没有什么区别,只是把print换成了file1.wirte而已。
完整代码如下:
import requests
import re
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company
res = requests.get(url, headers=headers).text
# print(res)
p_info = '<p class="c-author">(.*?)</p>'
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
info = re.findall(p_info, res, re.S)
href = re.findall(p_href, res, re.S)
title = re.findall(p_title, res, re.S)
source = [] # 先创建两个空列表来储存等会分割后的来源和日期
date = []
for i in range(len(info)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
print(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')')
print(href[i])
file1 = open('E:\\数据挖掘报告.txt', 'a')
file1.write(company + '数据挖掘completed!' + '\n' + '\n')
for i in range(len(title)):
file1.write(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')' + '\n')
file1.write(href[i] + '\n') # '\n'表示换行
file1.write('——————————————————————————————' + '\n' + '\n')
file1.close()
companys = ['华能信托', '阿里巴巴', '万科集团', '百度集团', '腾讯', '京东']
for i in companys:
baidu(i)
print(i + '百度新闻爬取成功')
print('数据获取及生成报告成功')
补充一些文件路径的常用知识点:
(1) 文件夹路径通常写两个反斜杠:“\”,这是因为反斜杠在Python里其实有特殊意义,比如说‘\n’表示换行,用两个反斜杠‘\’可以取消单个反斜杠的特殊含义。比如在E盘创建一个叫作“舆情报告”的文件夹,然后可以把文件路径写成:E:\舆情报告\数据挖掘报告.txt。
虽然在这个例子里,并没有什么特殊的类似\n的内容,所以也可以直接写:E:\舆情报告\数据挖掘报告.txt,但用两个反斜杠是写文件夹路径的一个好的编程习惯。
(2) 除了用两个反斜杠来取消一个反斜杠的特殊意义外,还可以在文件路径这个字符串前面加一个r,这样字符串里的反斜杠也不再具有特殊含义,代码如下:
file1 = open(r'E:\舆情报告\数据挖掘报告.txt', 'a')
(3) 如果只写一个文件名的话,比如直接写“数据挖掘报告.txt”,这个便是相对路径(之前的路径叫作绝对路径),也即代码所在的文件夹,最后会在代码所在文件夹生成一个txt文件。
3.1 异常处理实战
有时虽然代码写的比较完善,但是谁也不知道网页结构会有什么预想不到的状况,以及或者说突然网卡了或者网断了导致访问网站失败,那么为了防止程序因为很偶然的异常情况而终止运行,就得用之前所讲的try except异常处理语句来解决,代码如下:
companys = ['华能信托','阿里巴巴','万科集团','百度','腾讯','京东']
for i in companys:
try:
baidu(i)
print(i + '百度新闻爬取成功')
except:
print(i + '百度新闻爬取失败')
这样如果baidu()这个函数出现异常了,比如像上面提到的出现了一个异常新闻,它就不会因为程序异常而停止整个程序的运行,比如爬取万科失败的时候,它会执行except的操作,打印输出:万科百度新闻爬取失败。
3.2 24小时实时爬取实战
我们已经可以进行批量爬取以及通过异常处理来避免程序中断了,那么倘若想24小时不间断地对每家公司进行实时爬取,那么该如何操作了,这个就会用到之前提过的while函数了。
只要写一行while True代码便可以让代码一直执行,代码如下:
while True:
具体代码如下:
while True:
companys = ['华能信托','阿里巴巴','万科集团','百度','腾讯','京东']
for i in companys:
try:
baidu(i)
print(i + '百度新闻爬取成功')
except:
print(i + '百度新闻爬取失败')
这样程序就会24小时不间断的运行下去了,而且因为我们加上了异常处理语句,所以就算出现了什么异常新闻,整个程序也不会中断,从而实现24小时不间断运行。
如果不需要一直运行,比如只需要它每3小时跑一次程序,可以引入time模块即可,然后通过time.sleep(10800)即可实现该目的,代码如下:
import time
while True:
companys = ['华能信托','阿里巴巴','万科集团','百度','腾讯','京东']
for i in companys:
try:
baidu(i)
print(i + '百度新闻爬取成功')
except:
print(i + '度新闻爬取失败')
time.sleep(10800)
先用import引入time模块,time.sleep()括号里面的数字单位是秒,所以time.sleep(10800)的意思就是休息10800秒,也就是休息3小时的意思。这样for循环执行完一遍之后,就会自动休息3小时再进行程序运行。注意time.sleep(10800)这一行代码不要写到for循环里面去,它要和for在竖的方向上并排,也就是缩进相同,因为是要等for循环执行完了,才执行time.sleep操作。
完整代码如下所示:
import requests
import re
import time
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company
res = requests.get(url, headers=headers).text
# 1节讲过的数据提炼、清洗等相关代码,注意缩进,写到函数里面来
while True:
companys = ['华能信托', '阿里巴巴', '百度集团', '腾讯集团', '万科集团']
for i in companys:
try:
baidu(i)
print(i + '百度新闻爬取成功')
except:
print(i + '百度新闻爬取失败')
time.sleep(3600)
完整代码如下:
import requests
import re
import time
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=' + company
res = requests.get(url, headers=headers).text
# print(res)
p_info = '<p class="c-author">(.*?)</p>'
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
info = re.findall(p_info, res, re.S)
href = re.findall(p_href, res, re.S)
title = re.findall(p_title, res, re.S)
source = [] # 先创建两个空列表来储存等会分割后的来源和日期
date = []
for i in range(len(info)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
print(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')')
print(href[i])
while True:
companys = ['华能信托', '阿里巴巴', '万科集团', '百度集团', '腾讯']
for i in companys:
try:
baidu(i)
print(i + '百度新闻爬取成功')
except:
print(i + '百度新闻爬取失败')
time.sleep(3600) # 每3600秒运行一次,即3小时运行一次,注意缩进
至此便实现多家上市公司24小时不间断的数据挖掘了,有的读者可能会有这样的疑问,这里只爬取了百度新闻的第一页会错过其他重要新闻吗?答案是不会的,因为这边实现的是24小时不间断爬取,所以只要出现新的新闻就可以捕捉到。有读者可能又有疑问了,那这样一直爬,会不会爬到很多重复新闻呢?答案是会,的确在不间断的爬取中会爬取到重复的内容,那么能不能在之后的爬取过程中把重复的信息给剔除了呢?答案也是能,至于如何去重,需要在之后讲到数据库的时候给大家详细讲解。
4.1 按时间顺序爬取百度新闻
之前爬取百度新闻的时候,并不是按照时间顺序来获取新闻的,这是因为百度新闻默认通过“焦点排序”,也就是把热点新闻放在最上面,如下图所示:
有的读者可能说想按照时间顺序来获取新闻,这个也是完全可以的。只需要在上面这个红色框里选择“按时间排序”,那么就能把新闻按照时间来进行排序,效果图如下所示:
点击确认,记住该选择,之后打开百度新闻的默认就是按时间排序了。
此时按时间排序的网址url为:
https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=阿里巴巴
之前按焦点排序的网址url为:
https://www.baidu.com/s?tn=news&rtt=1&bsst=1&cl=2&wd=阿里巴巴
可以看到它们唯一的区别就在于中间的rtt=的内容,一个是rtt=4,一个rtt=1,那么我们就清楚,如果中间rtt=4就表示按时间排序,如果rtt=1就表示按焦点排序。那么如果要写按时间排序的代码就很容易了,只要把之前学过的代码里的url中的rtt=1换成rtt=4即可。如下所示:
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=' + company
4.2 一次性爬取多页(供参考学习)
其实实现24小时爬取后,已经不太需要爬取多页了,虽然只爬第一页,但实时都在爬就不会丢失信息了,但是有的读者希望能一次性爬取多页信息,所以作为补充知识点讲解一下。
(1) 爬取一家公司的多页
其实爬取多页的技巧和按时间顺序爬取比较类似,都是在网址url上做文章。我们首先来看下爬取阿里巴巴百度新闻的第一页的网址链接:
https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=阿里巴巴
在网页最下面,选择第二页,网址如下,其中删掉了对链接跳转不影响的一些内容。
https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=阿里巴巴&pn=10
发现好像也没什么规律可寻,让我们再看看第三页,网址如下。
https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=阿里巴巴&pn=20
发现这个从第二页开始,每一个网页的链接,其实只有一个内容”&pn=“有变化(pn其实是page number的缩写),而且是一个0,10,20的递增规律,别的内容都没有变化,那么我们可以推断这个就是爬取多页的一个关键。有人会说,那第一页的网址和后面的不太一样,其实这个在网页链接里,有很多东西都不是必须的,比如在第一页里,它就不用写”&pn=“就可以访问。如果实在好奇,可以自己删掉一些内容看是否还能访问就知其是否必须。
回到第一页的问题,可以仿照第二页造一个第一页的链接,看是否能够访问成功,按递增规律能够猜到第一页”&pn=“应该是00,所以构造一个第一页的网址为:
https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=阿里巴巴&pn=00
试着点击一下,发现的确是第一页的内容,那么就可以根据这个规律来进行一次性爬取多个网页了,构造如下url,代码如下:
def baidu(page):
num = (page - 1) * 10
url = 'https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=阿里巴巴&pn=' + str(num)
res = requests.get(url, headers=headers).text
# 1小节其他相关爬虫代码
for i in range(10): # i是从0开始的序号,所以下面要写i+1
baidu(i+1)
print('第' + str(i+1) + '页爬取成功')
其中注意num是数字,所以在做字符串拼接的时候得用str函数转换下。
完整代码如下:
import requests
import re
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
# 爬取一个公司的多页
def baidu(company, page):
num = (page - 1) * 10
url = 'https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=' + company + '&pn=' + str(num) # rtt=4则是按时间顺序爬取,rtt=1为按焦点排序
res = requests.get(url, headers=headers).text
# 其他相关爬虫代码
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
p_info = '<p class="c-author">(.*?)</p>'
href = re.findall(p_href, res, re.S)
title = re.findall(p_title, res, re.S)
info = re.findall(p_info, res, re.S)
source = [] # 先创建两个空列表来储存等会分割后的来源和日期
date = []
for i in range(len(info)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
print(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')')
print(href[i])
for i in range(10): # i是从0开始的序号,所以下面要写i+1,这里一共爬取了10页
baidu(keyword, i+1)
print('第' + str(i+1) + '页爬取成功')
(2) 爬取多家公司的多页
上面是爬取一家公司的多页,如果想爬取多家公司的多列,则可以给函数设置两个参数,通过两个for循环进行多家公司多页的批量爬取,代码如下:
def baidu(company, page):
num = (page - 1) * 10
url = 'https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=' + company + '&pn=' + str(num)
res = requests.get(url, headers=headers).text
# 1小节其他相关爬虫代码
companys = ['华能信托','阿里巴巴','万科集团','百度集团','腾讯','京东']
for company in companys:
for i in range(20):
baidu(company, i+1)
print(company + '第' + str(i+1) + '页爬取成功')
完整代码如下:
import requests
import re
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
# 爬取多个公司的多页, 可以给函数传入两个参数,供参考
def baidu(company, page):
num = (page - 1) * 10
url = 'https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=' + company + '&pn=' + str(num) # rtt=4则是按时间顺序爬取,rtt=1为按焦点排序
res = requests.get(url, headers=headers).text
p_info = '<p class="c-author">(.*?)</p>'
info = re.findall(p_info, res, re.S)
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
href = re.findall(p_href, res, re.S)
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
title = re.findall(p_title, res, re.S)
source = [] # 先创建两个空列表来储存等会分割后的来源和日期
date = []
for i in range(len(info)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
info[i] = re.sub('<.*?>', '', info[i])
source.append(info[i].split(' ')[0])
date.append(info[i].split(' ')[1])
source[i] = source[i].strip()
date[i] = date[i].strip()
print(str(i + 1) + '.' + title[i] + '(' + date[i] + '-' + source[i] + ')')
print(href[i])
companys = ['华能信托', '阿里巴巴', '万科集团', '百度集团', '腾讯', '京东']
for company in companys:
for i in range(10):
baidu(company, i+1)
print(company + '第' + str(i+1) + '页爬取成功')
4.3 爬取总新闻数:
其实这个功能在商业实战中,我们不会用这个数据,但是用来做展示还是挺酷的:当你在程序中展示下图的时候,没有接触过爬虫的人会觉得很厉害的哟。
但其实要做出这个效果出来非常简单,我们下面就来给大家演示。
首先,我们利用F12来获取新闻总数的相关信息:
或者直接右击选择“查看网站源代码”,Ctrl + F搜索“68,700”,也能找到相关位置:
代码如下:
p_num = '<span class="nums">(.*?)</span>'
num = re.findall(p_num, res, re.S)
num = num[0] #虽然num只有一个元素,但findall出来的还是列表,所以得这样调用
print(num + ',最近20篇新闻展示如下:')
有个小注意点,这个num虽然只有一个元素,但是仍然是一个列表,因为findall出来的内容,无论多少元素都是个列表,所以这边我们得写num = num[0]来提取该元素(列表的第一个元素的序号为0)。而且第二行的re.S(用来忽略换行符)都可以不用加,因为它不存在换行,我们在正式代码里把re.S删掉。别的内容就不太用改了,整段代码如下(为了简洁,我们把爬取日期和来源的相关代码先删掉,你可以自己加上去):
import requests
import re
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'}
def baidu(company):
url = 'https://www.baidu.com/s?tn=news&rtt=4&bsst=1&cl=2&wd=' + company # 其中rtt参数是关键,rtt=4则是按时间顺序爬取,rtt=1为按焦点排序
res = requests.get(url, headers=headers).text
# print(res)
p_href = '<h3 class="c-title">.*?<a href="(.*?)"'
p_title = '<h3 class="c-title">.*?>(.*?)</a>'
href = re.findall(p_href, res, re.S)
title = re.findall(p_title, res, re.S)
p_num = '<span class="nums">(.*?)</span>'
num = re.findall(p_num, res)
num = num[0] # 虽然num只有一个元素,但findall出来的是列表,所以得这样调用
print(company + '舆情监控completed!')
print(num + ',最近10篇新闻展示如下:')
for i in range(len(title)):
title[i] = title[i].strip()
title[i] = re.sub('<.*?>', '', title[i])
print(str(i + 1) + '.' + title[i])
print(href[i])
print('——————————————————————————————') # 这个是当分隔符使用
companys = ['阿里巴巴', '万科集团', '百度', '腾讯', '京东']
for i in companys:
try:
baidu(i)
print(i + '该公司百度新闻爬取成功')
except:
print(i + '该公司百度新闻爬取失败')
添加完这几行代码,我们就可以轻松的获取一共多少篇新闻了,这样我们也可以在小伙伴面前展示了。
讲到这里,Python基础课就告一段落啦,虽然说是叫做Python基础课,其实它也可以叫做商业爬虫入门课了。我这边给大家留个大作业,算是作为一个学业总结。
Python基础课程大作业:
爬取搜狗新闻(其实它就是搜狐新闻的内容),网址如下:https://news.sogou.com/。具体任务如下:
1.批量爬取如下公司:华能信托,阿里集团,百度集团,腾讯,京东,万科集团,华为集团,格力集团,苹果公司,谷歌,亚马逊公司的舆情情况;
2.要求爬取新闻标题,新闻链接,发布日期和新闻来源;
3.要求实现24小时实时爬取,以及异常情况自动处理;
4.要求将爬取到的结果自动生成txt舆情报告
5.在txt舆情报告以及Python程序运行的第一行写上作者的名字及完成日期。
这个大作业我相信如果你仔细学了之前的内容话,那么完成这个任务应该不会有太大的困难,如果你这个搜狗新闻的内容能够完成了话,那么很多网站对你来说都是小菜一碟了,比如说证券日报,证券时报等网站,你都可以自己试一试了。其中大作业的代码我也放到了课程附带的源代码里了,大家做完可以自己比对一下。
关于进阶课,其实可以说Python商业爬虫案例实战课了,感兴趣的同学,可以访问该网站:https://shimo.im/docs/DApBD1rEwvwuLRKp/ 查看华小智系列课程的课表,它属于系列4:Python商业爬虫案例实战,主要会在基础课的基础上补充数据整理,数清洗及优化,舆情评分系统,IP代理池实战,网页结构详解,网页内容下载,模拟账号密码登陆,数据库详解,数据可视化,本地及云服务器部署,自动生成word舆情报告,舆情自动预警邮件功能,以及一个神器的介绍,学完那个神器,可以说市面上主流的网站都可以爬取了,只要没有太过麻烦的验证登陆即可,这边埋个伏笔,暂且不表。
这里将介绍一下Python进阶的一些其他应用,主要介绍五块内容:
1、Python量化金融初窥 《Python拓展知识》,可复制链接后用石墨文档 App 或小程序打开);
2、大数据分析及机器学习 《Python拓展知识》,可复制链接后用石墨文档 App 或小程序打开);
3、RPA机器处理自动化 《Python拓展知识》,可复制链接后用石墨文档 App 或小程序打开),也即很火的RPA智能AI机器人相关知识;
4、Python文字识别&人脸识别 《Python拓展知识》,可复制链接后用石墨文档 App 或小程序打开);
5、Python语音识别 《Python拓展知识》,可复制链接后用石墨文档 App 或小程序打开)。
其中1、2、4、5版块会讲代码让大家有个初步的了解。
点击上方蓝色字体或者下方链接即可跳转到Python进阶相关教材链接:
https://shimo.im/docs/8TYdkYDXVVy8kxhR/ 《Python拓展知识》