目录
1.认识Python网络爬虫
网络爬虫是一种互联网信息的自动化采集程序,主要作用是代替人工对互联网中的数据进行自动采集与整理,以快速地、批量地获取目标数据。
从技术手段来说,网络爬虫有多种实现方案,如PHP、Python(Urllib、requests、scrapy、selenium…)…但,网络爬虫的难点并不在于网络爬虫本身,而在于网页的分析与爬虫的反爬攻克问题。
2.网络爬虫步骤
- 明确目标 (确定你准备爬取哪个网站的内容)
- 爬 (下载该网页源代码到本地内存中,将网站的所有内容全部爬下来)
- 取 (通过表达式取出我们想要的数据)
- 处理数据(按照我们想要的方式存储和使用)
3.网络爬虫常见类型与应用领域
如下所示,是网络爬虫可以做的一些事情:
- 批量采集某个领域的招聘数据,对某个行业的招聘情况进行分析
- 批量采集某个行业的电商数据,以分析出具体热销商品,进行商业决策
- 采集目标客户数据,以进行后续营销
- 批量爬取腾讯动漫的漫画,以实现脱网本地集中浏览
- 开发一款火车票抢票程序,以实现自动抢票
4.数据提取技术基础:正则表达式基础
网络爬虫程序在将网页爬下来之后,其中还有一个关键的步骤就是需要对我们关注的目标信息进行提取,而表达式一般就是用于信息筛选提取的工具。这里简要介绍一下正则表达式的使用。
基础1:
全局匹配函数使用格式: re.compile(正则表达式).findall(源字符串)
字符 | 含义 |
普通字符 | 正常匹配 |
\w | 匹配字母、数字、下划线 |
\W | 匹配除字母、数字、下划线 |
\t | 匹配制表符 |
\s | 匹配空白字符 |
\S | 匹配除空白字符 |
\n | 匹配换行符 |
\d | 匹配十进制数字 |
\D | 匹配除十进制数字 |
[ab89x] | 原子表,匹配ab89x中的任意一个 |
[^ab89x] | 原子表,匹配除ab89x以外的任意一个字符 |
实例1:
源字符串:"aliyunedu"
正则表达式:"yu"
匹配结果: yu
源字符串:'''aliyun
edu'''
正则表达式:"yun\n"
匹配结果: yun\n
源字符串:"aliyu89787nedu"
正则表达式:"\w\d\w\d\d\w"
匹配结果: u89787
源字符串:"aliyu89787nedu"
正则表达式:"\w\d[nedu]\w"
匹配结果: 87ne
基础2:
字符 | 含义 |
+ | 前一个字符出现1\多次 |
| | 模式选择符或 |
{n} | 前一个字符恰好出现n次 |
{n,m} | 前一个字符至少n,至多m次 |
{n,} | 前一个字符至少n次 |
^ | 匹配开始位置 |
? | 前一个字符出现0\1次 |
. | 匹配除换行外任意一个字符 |
* | 前一个字符出现0\1\多次 |
() | 模式单元,通俗来说就是:想提取出什么内容,就在正则中用小括号将其括起来 |
$ | 匹配结束位置 |
实例2:
源字符串:'''aliyunnnnji87362387aoyubaidu'''
正则表达式:"ali..."
匹配结果: aliyun
正则表达式:"^li..."
匹配结果: None
正则表达式:"^ali..."
匹配结果: aliyun
正则表达式:"bai..$"
匹配结果: baidu
正则表达式:"ali.*"
匹配结果: aliyunnnnji87362387aoyubaidu
Tips:默认贪婪,即默认尽可能多地进行匹配
正则表达式:"aliyun+"
匹配结果: aliyunnnn
正则表达式:"aliyun?"
匹配结果: aliyun
正则表达式:"yun{1,2}"
匹配结果: yunn
正则表达式:"^al(i..)."
匹配结果: iyu
基础3:
贪婪模式:尽可能多地匹配
懒惰模式:尽可能少地匹配,精准模式
默认贪婪模式
如果出现如下组合,则代表为懒惰模式:
*?
+?
实例3:
源字符串:"poytphonyhjskjsa"
正则表达式:"p.*y"
匹配结果:? poytphony
为什么? 默认贪婪模式
源字符串:"poytphonyhjskjsa"
正则表达式:"p.*?y"
匹配结果: ['poy', 'phony']
为什么? 懒惰模式,精准匹配
基础4:
模式修正符:在不改变正则表达式的情况下通过模式修正符使匹配结果发生更改
re.S 让 . 也可以匹配多行
re.I 匹配时忽略大小写
实例4:
源字符串:"Python"
正则表达式:"pyt"
匹配方式:re.compile("pyt").findall("Python")
匹配结果: []
源字符串:"Python"
正则表达式:"pyt"
匹配方式:re.compile("pyt",re.I).findall("Python")
匹配结果: Pyt
源字符串:string="Python"
正则表达式:"pyt"
匹配方式:re.compile("pyt",re.I).findall("Python")
匹配结果: Pyt
源字符串:string="""我是阿里云大学
欢迎来学习
Python网络爬虫课程
"""
正则表达式:pat="阿里.*?Python"
匹配方式:re.compile(pat).findall(string)
匹配结果: []
源字符串:string="""我是阿里云大学
欢迎来学习
Python网络爬虫课程
"""
正则表达式:pat="阿里.*?Python"
匹配方式:re.compile(pat,re.S).findall(string)
匹配结果: ['阿里云大学\n欢迎来学习\nPython']
5.实战:批量爬取天善智能学院课程数据
使用上面的知识编写一个简单的网络爬虫:爬取天善智能学院课程数据
5.1 明确目标 (确定你准备爬取哪个网站的内容)
目标网址:https://edu.hellobi.com/
目标数据:取出该网站所有课程的 课程名、课程讲师、课程价格,也就是下图红框中的内容。
5.2 爬(下载该网页源代码到本地内存中)
通过如下代码我们就可以将该网页的源代码全部爬取下来,保存到本地内存中:
#导入包urllib.request
import urllib.request
#设定要爬取的网站url
thisurl="https://edu.hellobi.com/course/308"
#使用函数urlopen访问该网站,使用函数read将访问网站的源代码全部下载到内存中,使用函数decode设定UTF-8中文编码,并忽略一些错误
data=urllib.request.urlopen(thisurl).read().decode("utf-8","ignore")
到这一步我们已经将下图中的网页源代码下载到了本地内存中,在网页 右键->查看网页中的源代码,即可看到爬取的内容。
5.3 取(通过正则表达式取出我们想要的数据)
首先需要分析网页,选中要取出的内容,在源代码中ctrl+f搜索要取出的内容,即可看到该内容在网页源代码中的位置,如下:
取具有唯一性的代码段进行正则匹配,使用如下代码,取出这门课的课程名:
#导入包urllib.request
import urllib.request
#设定要爬取的网站url
thisurl="https://edu.hellobi.com/course/308"
#使用urlopen函数访问该网站,使用read函数将访问网站的源代码全部下载到内存中,使用decode函数设定UTF-8中文编码,并忽略一些错误
data=urllib.request.urlopen(thisurl).read().decode("utf-8","ignore")
#根据源代码编写匹配的正则表达式,(.*?)就是我们要取出的部分
title_pat='<li class="active">(.*?)</li>'
#使用re包中的compile函数编译正则匹配表达式,re.S代表可以换行匹配,使用findall函数选定数据集,也就是爬取的所有源代码
title=re.compile(title_pat,re.S).findall(data)
#打印出课程名
print(title)
运行结果如下:
价格和老师的提取办法依此类推如下:
价格的源代码:
老师所在的源代码:
使用如下代码,取出这门课的课程名、价格、老师:
import urllib.request
import re
thisurl="https://edu.hellobi.com/course/308"
data=urllib.request.urlopen(thisurl).read().decode("utf-8","ignore")
title_pat='<li class="active">(.*?)</li>'
title=re.compile(title_pat,re.S).findall(data)
print(title)
price_pat='div class="course-price">.*?<sub>¥</sub>(.*?)<b></b></span>'
price=re.compile(price_pat,re.S).findall(data)
print(price)
teacher_pat='class="lec-name">(.*?)<'
teacher=re.compile(teacher_pat,re.S).findall(data)
print(teacher)
运行结果如下:
我们的目标是要取出所有课程的名字,价格以及老师,可以发现每个课程的网址url只有最后的数字不同,所以这里可以使用for循环取出所有课程的数据。
最终代码如下:
import urllib.request
import re
for i in range(0,1000):
thisurl="https://edu.hellobi.com/course/"+str(i+1)
data=urllib.request.urlopen(thisurl).read().decode("utf-8","ignore")
title_pat='<li class="active"(.*?)</li>'
teacher_pat='class="lec-name">(.*?)<'
price_pat='div class="course-price">.*?<sub>¥</sub>(.*?)<b></b></span>'
title=re.compile(title_pat,re.S).findall(data)
if(len(title)>0):
title=title[0]
else:
continue
teacher=re.compile(teacher_pat,re.S).findall(data)
if(len(teacher)>0):
teacher=teacher[0]
else:
teacher="缺失"
price=re.compile(price_pat,re.S).findall(data)
if(len(price)>0):
price=price[0]
else:
price="免费"
print(title)
print(price)
print(teacher)
print("--------------")