8月1日开发者日志爬虫初识
8月1日开发者日志爬虫初识
讲在课前
课程
异步会用到协程
大纲
Anacanda:一款集成环境,集成的都是基于数据分析和机器学习的环境(模块)
jupyter notework : 可视化
requests
scrapy
jupyter notebook 快捷键
-
cell
添加 一个cell : a b 删除cell : x 进入编辑 : 双击 切换cell 模式: y : markdown -> code m : code -> markdown tab : 执行cell : shift + enter 打开帮助文档 : shift + tab
爬虫定义:
就是通过编写程序模拟浏览器上网,然后让其去互联网上抓取数据的过程
- 浏览器就是一款天然的爬虫工具
爬虫分类
-
通用爬虫 : 爬取一整张页面源码数据 content text read (response)
搜索引擎用的比较多(抓取系统(爬虫))
-
聚焦爬虫 : 爬取的是一张页面中局部的数据 (数据解析)
-
增量式爬虫 :
- 用于监测网站数据更新的情况,从而爬取网站中最新更新出来的数据
-
反爬机制:(门户网站)
-
反反爬策略:
-
第一个反爬机制:
-
robots.txt协议: (防君子不防小人)
User-agent请求载体的身份标识 : 1.浏览器 2.爬虫工具
allow: 可爬, disallow 不可爬
自己写的爬虫权限:根目录不可爬
-
http协议和https协议
-
http 协议: 就是客户端和服务端进行数据交互的形式
-
常用的请求头:
-
User-agent请求载体的身份标识
-
content-type:
-
Connection: keep-alive (http1.1之后都是长链接,有时间)
: close
-
-
https: 加密的http(http + ssl)
相对于http更安全,但是性能较低
-
对称密钥加密:客户端设立一种加密方式(用户名,密码)->密文+密钥发给服务端
- 问题 : 一起发送,安全性低,被fiddler拦截了,解析
-
非对称密钥加密:服务器给客户公钥,客户端以此加密了,传密文给服务端
-
问题: 1,效率低,通信实现
2,非服务器端模拟公钥发送,也造成被劫持
-
-
证书密钥加密
给服务器的公钥认证,就不是假的了,传过去客户端
证书:
12306不是同一家的证书机构,国家颁发的,浏览器没认可
-
-
案例
网页采集
爬取豆瓣/肯德基的相关数据
药监总局企业信息的爬取
爬虫模块requests
网络请求的模块,模拟浏览器发请求的
-
urllib (老的爬取,封装没有这么高级)
知道如何发起请求就可(老师博客)
-
编码流程
- 指定url
- 发起了请求
- 获取响应数据
- 持久化存储
-
爬取搜狗首页的页面源码数据
import requests # 获取url url = 'https://www.sogou.com/' # 发起请求,:返回值是一个response response = requests.get(url=url) # 获取响应数据: text返回的是字符串形式的响应数据(页面源码数据) page_text = response.text # 持久化存储 with open('sogou.html','w', encoding='utf-8') as fp: fp.write(page_text)
因为没有页面渲染,所以生成的html,这个模样,但是只要数据,就行了(有可能会好看排班,看爬下来的数据如何了)
#简易的网页采集器 url = 'https://www.sogou.com/web' #设定动态的请求参数 wd = input('enter a key word:') params = { 'query':wd } #参数2:params是一个字典,是用来处理动态请求参数 response = requests.get(url=url,params=params) page_text = response.text fileName = wd+'.html' # with open(fileName,'w',encoding='utf-8') as fp: # fp.write(page_text) # print(fileName,'下载成功!') print(page_text) #分析:爬取的数据有乱码 爬取的数据有缺失
显示:
乱码 --> 给resoponse = encoding('utf-8') # 改了编码格式
#修改原始的响应数据的编码 response.encoding = 'utf-8' page_text = response.text
拒绝访问:
显示:
搜狗队请求载体身份标识做了检查
- ua 检测:搜狗使用的反爬机制
- ua 伪装 headers = {} #常识
#UA伪装 headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36' } #参数2:params是一个字典,是用来处理动态请求参数 response = requests.get(url=url,params=params,headers=headers) #将headers作用的get方法的第三个参数中 #修改原始的响应数据的编码
完整的简易的网页采集器代码
#简易的网页采集器 url = 'https://www.sogou.com/web' #设定动态的请求参数 wd = input('enter a key word:') params = { 'query':wd } #UA伪装 headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36' } #参数2:params是一个字典,是用来处理动态请求参数 response = requests.get(url=url,params=params,headers=headers) #将headers作用的get方法的第三个参数中 #修改原始的响应数据的编码 response.encoding = 'utf-8' page_text = response.text fileName = wd+'.html' with open(fileName,'w',encoding='utf-8') as fp: fp.write(page_text) print(fileName,'下载成功!')
需求:爬取肯德基的餐厅位置信息
http://www.kfc.com.cn/kfccda/storelist/index.aspx
- 动态加载的数据:是另一个新的请求请求到的数据
xml里的http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword
Headers 里 from data
cname:
pid:
keyword: 北京
pageIndex: 1
pageSize: 10
1 2000 分析 都出来了
爬取肯德基的地址程序
#UA伪装
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
}
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
city = input('enter a city name:')
#该字典是用来处理封装post请求的请求参数
data = {
"cname": '',
'pid': '',
'keyword': city,
'pageIndex': '1',
'pageSize': '2000',
}
response = requests.post(url=url,data=data,headers=headers)
#json()返回的是序列化之后的json对象.
json_data = response.json()
for dic in json_data['Table1']:
print(dic['addressDetail'])
爬取
爬取页面之前:
- 验证要爬取的数据,是否为当前页面动态加载的?另一个请请求到的!
- 是-不可爬 否,可爬
- 如何验证页面中的局部数据是否为动态加载呢?
- 首先在页面赋值一部分的页面内容,然后在通过抓包工具定位到url指定的数据包,在数据的response中进行搜索,没有则为动态数据
http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList
http://125.35.6.84:81/xk/itownet/portal/dzpz.jsp?id=3433178cbd7645909317d05199be3e20
爬取动态网页
搜索动态网址:'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
}
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':'',
}
json_date= requests.post(url=url,data=data,headers=headers).json()['list']
for data in json_date:
print(data['ID'])
数据格式:
获得ID,进入详细的每一个页面
因为是根据id合成新的url ---> http://125.35.6.84:81/xk/itownet/portal/dzpz.jsp?id=f0cf7be12d804bbf9b663a5537fdd72a(不是根据动态获得的这个吗?)
http://125.35.6.84:81/xk/itownet/portal/dzpz.jsp?id=800618396a69448ab7f5162c77f89bf2 # GET
或者是http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById,
不是搜错了,搜有用的数据,不是随便的格式的值.response(返回的是html网页)
然后会定位到返回的请求的url,response(返回的是字典的数据)
然后再找form_data,找传的数据.就是提取的ID
数据格式:
for data in json_date:
id = data['ID']
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {'id': id}
b_data = requests.post(url=url,data=data , headers=headers).json()
print(b_data['businessPerson'],b_data['epsName'])
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {'id': idd}
b_data = requests.post(url=url, headers=headers,data=data).json()
print(b_data['businessPerson'],b_data['epsName'])
说是not list的错误,但是打印出来就是只打印第一页的内容
而且,当只写一页的时候没错误,而且,可以打印在没有打印post第二页的网址的时候.
最终错误: url和上面重名了,改成urll 就好了,而且老师很细节的也设置成detail_url
完整版代码:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
}
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
for i in range(1,6):
data = {
'on': 'true',
'page': str(i),
'pageSize': '15',
'productName': '',
'conditionType': '1',
'applyname':'',
'applysn':'',
}
print(f'正在爬取第{i}页数据')
print('\n')
json_date= requests.post(url=url,data=data,headers=headers).json()
for i in json_date['list']:
idd = i['ID']
urll = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {'id':idd}
b_data = requests.post(url=urll,data=data,headers=headers).json()
print(b_data['businessPerson'], b_data['epsName'])
错误信息:
错误位置:
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {'id':idd}
b_data = requests.post(url=url,data=data,headers=headers).json()
print(b_data['businessPerson'], b_data['epsName'])
但是之前是对的,可以访问id,为什么不能访问之后的呢?(这个是对的,说明上面的代码没问题,下面的代码有问题,不应该往上面去找bug的)
哦,之前没用到url,url引起歧义了,而且id老师也给改成了_id,之前是id
http://localhost:8888/?token=
47602d77e35da9c700ebb2d712a12ed5c9bd468dcfaa2e02
爬药监:拔网线,连wifi
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
}
url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
for i in range(1,6):
data = {
'on': 'true',
'page': str(i),
'pageSize': '15',
'productName': '',
'conditionType': '1',
'applyname':'',
'applysn':'',
}
# print(f'正在爬取第{i}页数据')
# print('\n')
json_date= requests.post(url=url,data=data,headers=headers).json()
for i in json_date['list']:
idd = i['ID']
urll = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
data = {'id':idd}
b_data = requests.post(url=urll,data=data,headers=headers).json()
# print(b_data['businessPerson'], b_data['epsName'])
作业完成
import requests
url = 'https://movie.douban.com/j/chart/top_list?'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36'
}
count = 0
for i in range(0,240,20):
# print(i)
data = {
'type': '5',
'interval_id': '100:90',
'action':'' ,
'start': str(i),
'limit': '20',
}
json_date= requests.post(url=url,data=data,headers=headers).json()
for i in json_date:
count += 1
print(count,i['title'],i['score'])