爬虫+数据分析【day1】
学习方法
不要边听边记,不要花大把的时间记笔记。照抄笔记没有意义。
记忆的不深刻:用自己的话术记笔记,自己的话术要白话一点。只有自己有了深刻的理解,才能把它用白话讲出来,不理解才会背专业的话术。
课上一点笔记都不要做,课下看一遍老师的笔记,并按自己的理解与话术白话一点地做一个总结即可。不要过于担心自己的思路偏差,只要自己总结的概念在使用过程中没有任何问题就是对的思路。
day1
1 开发环境介绍
anaconda:基于数据分析和机器学习的集成环境
jupyter:anaconda 提供的一个基于浏览器的可视化开发的工具
2 jupyter的基本使用
在终端录入jupyter notebook的指令启动jupyter可视化的开发工具
jupyter notebook的指令录入对应的默认的目录结构就是终端对应的目录结构
new->text file:新建一个任意后缀的文本文件,可以写代码但不能执行,在终端里利用python工作可以执行。
new->python 3 :新建一个基于jupyter的源文件(xxx.ipynb)
ceil:jupyter源文件中的一个编辑行。
ceil是可以分为两种不同的模式:
- code模式:用来编写和执行代码
- mardown模式:编写笔记。里面写代码不能执行
快捷键的使用
插入ceil:按a、b
删除ceil:x
撤销上一次:z
执行ceil:shift+enter 不论是code模式还是markdown模式都需要执行才能看到最后的结果。
切换ceil的模式:
- y:将markdown模式的ceil切换成code模式
- m:将code切换为markdown
打开帮助文档
- shift+tab:快速知道方法的含义、参数、例子等
3 爬虫
概念:就是通过编写程序,让其模拟浏览器上网,然后去互联网上抓取数据的过程
- 模拟:浏览器就是一款天然的爬虫工具!
- 抓取::抓取一整张数据,抓取一整张数据中的局部数据
爬虫的分类:
- 通用爬虫(数据的爬取):抓取一整张页面源码数据
- 聚焦爬虫(数据解析):抓取局部的指定的数据。基于通用爬虫
- 增量式爬虫(数据的更新):监测网站数据更新的情况!抓取网站最新更新出来的数据。
- 分布式:
反爬机制
- 一些网站的后台会设定相关的机制阻止爬虫程序进行数据的爬取。
反反爬策略
- 爬虫需要制定相关的策略破解反爬机制,从而可以爬取到网站的数据。
第一个反爬机制
- robots协议: 存在于网站服务器的一个文本协议。指明了该网站中哪些数据可以爬取哪些不可以爬取。(防君子不防小人)

爬虫风险:
- 爬虫干扰了被访问网站的正常运营;
- 爬虫抓取了受到法律保护的特定类型的数据或信息
3.1 requests的基本操作
urllib模块:基于模拟浏览器上网的模块,网络请求模块。(基本没人用了)
requests模块:基于网络请求的模块。作用:模拟浏览器上网。
requests模块的编码流程:
- 指定url
- 发起请求
- 获取响应数据(爬取的数据)
- 对数据持久化存储
#爬取搜狗首页的页面源码数据
#1.爬取搜狗首页的页面源码数据
url = 'https://www.sogou.com/'
response = requests.get(url=url)
page_text = response.text #text返回的是字符串形式的响应数据
with open('./sogou.html','w',encoding='utf-8') as fp:
fp.write(page_text) //写到文件里
#分别对应如上四步
with open() as fp:
是 Python 中打开文件的一种常用方式。它的作用是打开一个文件,并将其赋值给一个变量 fp。
with关键字 可以在语句结束后,关闭文件流。不用with关键字,文件会被python垃圾回收关闭。
open(‘file’, mode)第一个参数是包含文件名的字符串。第二个参数是另一个字符串,其中包含一些描述文件使用方式的字符,如 ‘r’,表示文件只能读取,‘w’ 表示只能写入。encoding='utf-8'
以utf-8的格式存入
#简易的网页采集器
#2.简易的网页采集器
#涉及到的知识点:参数动态化,UA伪装,乱码的处理
word = input('enter a key word:') //输入我想搜素的
url = 'https://www.sogou.com/web'
#参数动态化:将请求参数封装成字典作用到get方法的params参数中
params = {
'query':word
}
response = requests.get(url=url,params=params)
page_text = response.text
fileName = word+'.html' //起一个名字,存爬取数据的文件
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(word,'下载成功!!!')
url = 'https://www.sogou.com/web?query=jay'
只能请求jay的,想我输入什么就请求什么–>参数动态化
- 上述代码出现的问题:
- 乱码问题
- 爬取数据丢失
#乱码处理
word = input('enter a key word:')
url = 'https://www.sogou.com/web'
#参数动态化:将请求参数封装成字典作用到get方法的params参数中
params = {
'query':word
}
response = requests.get(url=url,params=params)
#可以修改响应数据的编码
response.encoding = 'utf-8'#手动修改了响应对象的编码格式
page_text = response.text
fileName = word+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(word,'下载成功!!!')
显示 检测到异常的访问请求。
什么叫做异常的访问请求?
- 在爬虫中正常的访问请求指的是通过真实的浏览器发起的访问请求。
- 异常的访问请求:通过非浏览器发起的请求。(爬虫程序模拟的请求发送)
正常的访问请求和异常的访问请求的判别方式是什么?
- 是通过请求头中的User-Agent判别。
- User-Agent:请求载体的身份标识
- 目前请求的载体可以是:浏览器,爬虫
反爬机制:
- UA检测:网站后台会检测请求载体的身份标识(UA)是不是浏览器。
- 是:正常的访问请求
- 不是:异常的访问请求
- UA检测:网站后台会检测请求载体的身份标识(UA)是不是浏览器。
反反爬策略:
#UA伪装
word = input('enter a key word:')
url = 'https://www.sogou.com/web'
#参数动态化:将请求参数封装成字典作用到get方法的params参数中
params = {
'query':word
}
#UA伪装
headers = {
"User-Agent": 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36'
}
#将伪装的UA作用到了请求的请求头中
response = requests.get(url=url,params=params,headers=headers)
#可以修改响应数据的编码
response.encoding = 'utf-8'#手动修改了响应对象的编码格式
page_text = response.text
fileName = word+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(word,'下载成功!!!')
==总结==:
- get方法的参数:
- url
- params
- headers
- get方法的返回值:
- response
- response的属性:
- text:字符串形式的响应数据
3.2 动态加载的数据
#爬取豆瓣网中的电影详情数据
- url:https://movie.douban.com/typerank?type_name=%E7%A7%91%E5%B9%BB&type=17&interval_id=100:90&action=
- 涉及到的重点:动态加载数据
滚轮向下不断地加载有新的数据。网页地址没变点但页面刷新,做的是一个局部刷新,发动的是ajax的请求。
分析网站:
- 当滚轮滑动到底部的时候,页面会发起ajax请求,且请求到一组电影详情数据。
- 当滚轮不滑动的时候,页面显示的电影数据通过对浏览器地址栏的url发起请求是请求不到的。(当要爬数据时,先从开发者工具里看看当前url请求下的response有没有要爬取的信息)
动态加载的数据
- 可见非即可得
- 当我们对一个陌生的网站进行指定数据爬取之前,我们在写代码之前必须要做的一个事情就是校验你想要爬取的数据是否为动态加载的数据。
- 概念:通过非浏览器地址栏url请求到的数据(另外的一个新的请求请求到的数据),即地址栏的url实际上请求不到的
- 是动态加载的数据
- 基于抓包工具进行全局搜索,锁定动态加载数据对应的数据包即可。从数据包中提取请求的url和请求方式和请求参数。
- 怎么做:在任意一个network数据包上ctrl+F 搜索动态加载的数据定位
- 不是动态加载的数据
- 直接对地址栏的url发起请求就可以获取指定数据
- 是动态加载的数据
response.text返回的是字符串数据,序列化,用response.json(),就不会返回一个字符串对象,而是一个列表
该数据包的url是'https://movie.douban.com/j/chart/top_list'
,该数据包是get请求。
url = 'https://movie.douban.com/j/chart/top_list'
#参数动态化
params = {
"type": "17",
"interval_id": "100:90",
"action": "",
"start": "20",
"limit": "10",
}
response = requests.get(url=url,headers=headers,params=params)
page_text = response.json() #json返回的是序列号好的对象
#将电影名称和评分进行解析
for dic in page_text:
name = dic['title']
score = dic['score']
print(name+':'+score)

**==总结==**:
- 问题:如何检测页面中的数据是否为动态加载的数据?
- 基于抓包工具进行局部搜索
- 搜索到:不是动态加载数据
- 搜索不到:是动态加载数据
- 基于抓包工具进行局部搜索
#肯德基餐厅查询
分析:
通过测试发现,数据为动态加载数据
通过抓包工具的全局搜索捕获动态加载数据
基本所有的requests都要带上headers
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
data = {
"cname": "",
"pid": "",
"keyword": "北京",
"pageIndex": "1",
"pageSize": "10",
}
#参数:data是用来实现参数动态化,等同于get方法中的params参数的作用
response = requests.post(url=url,headers=headers,data=data)
page_text = response.json()
for dic in page_text['Table1']:
pos = dic['addressDetail']
print(pos)
目前只有当前页面的10条,想获取7页所有的数据
#想要获取所有页码对应的位置信息
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
for pageNum in range(1,8):
data = {
"cname": "",
"pid": "",
"keyword": "北京",
"pageIndex": str(pageNum),
"pageSize": "10",
}
#参数:data是用来实现参数动态化,等同于get方法中的params参数的作用
response = requests.post(url=url,headers=headers,data=data)
page_text = response.json()
for dic in page_text['Table1']:
pos = dic['addressDetail']
print(pos)
#爬取药监总局中的企业详情数据
需求:爬取药监总局中的企业详情数据,每一家企业详情页对应的详情数据(爬取前5页企业)
分析:
- 先看企业详情页数据是否为动态加载数据?
- 基于抓包工具进行局部搜索。发现为动态加载数据
- 捕获动态加载的数据
- 基于抓包工具进行全局搜索。
- 定位到的数据包提取的
- url:
- 请求参数:
- id: 536878abac734332ae06dcb1a3fbd14a
- id: 950d66fbf8714fbc9e799010e483d2d5
- 结论:每一家企业详情数据对应的请求url和请求方式都是一样的,只有请求参数id的值不一样。
- 如果我们可以将每一家企业的id值捕获,则就可以将每一家企业详情数据进行爬取。
- 捕获企业的id
- 企业的id表示的就是唯一的一家企业。我们就猜测企业id可能会和企业名称捆绑在一起。
- 在首页中会有不同的企业名称,则我们就基于抓包工具对首页的数据包进行全局搜索(企业名称)
- url:http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList
- 方式:post
- 请求参数:
- on=true&page=1&pageSize=15&productName=&conditionType=1&applyname=&applysn=
- 先看企业详情页数据是否为动态加载数据?
#获取每一家企业的id值,去首页分析查找对应企业的id值
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
data = {
'on': 'true',
'page': '1',
'pageSize': '15',
'productName': '',
'conditionType': '1',
'applyname': '',
'applysn': '',
}
response = requests.post(url=url,headers=headers,data=data)
all_company_list = response.json()['list']
for dic in all_company_list:
_id = dic['ID']
# print(_id)
#将id作为请求企业详情数据url的请求参数 在for循环内
detail_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {
'id':_id
}
response = requests.post(url=detail_url,headers=headers,data=data)
company_detail_dic = response.json()
person_name = company_detail_dic['businessPerson']
addr = company_detail_dic['epsProductAddress']
print(person_name,addr)
#捕获多页数据
#获取每一家企业的id值,去首页分析查找对应企业的id值
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
for page in range(1,6):
data = {
'on': 'true',
'page': str(page),
'pageSize': '15',
'productName': '',
'conditionType': '1',
'applyname': '',
'applysn': '',
}
response = requests.post(url=url,headers=headers,data=data)
all_company_list = response.json()['list']
for dic in all_company_list:
_id = dic['ID']
# print(_id)
#将id作为请求企业详情数据url的请求参数
detail_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {
'id':_id
}
response = requests.post(url=detail_url,headers=headers,data=data)
company_detail_dic = response.json()
person_name = company_detail_dic['businessPerson']
addr = company_detail_dic['epsProductAddress']
print(person_name,addr)
data和params的区别,**==data对应post方法,params对应get方法==**,区别仅此而已,没有其他区别
3.3 爬取图片数据
#站长素材图片数据爬取
两种方式:
- 方式1:requests
- 方式2:urllib
#requests
url = 'http://pics.sc.chinaz.com/files/pic/pic9/201908/zzpic19447.jpg'
response = requests.get(url=url,headers=headers)
img_data = response.content #content返回的是bytes类型的响应数据
with open('./123.png','wb') as fp:
fp.write(img_data)
#urllib
from urllib import request
url = 'http://pics.sc.chinaz.com/files/pic/pic9/201908/zzpic19447.jpg'
request.urlretrieve(url=url,filename='./456.png')
注意#urllib 就是request
没有s
request.urlretrieve
- 问题:两种图片爬取的方式的主要区别有哪些?
- requests的方式可以实现UA伪装,而urlib无法实现UA伪装
如何批量获取图片url地址
用正则进行数据解析