爬虫相关介绍
- 什么是爬虫
- 就是编写程序,模拟浏览器上网,让其去互联网中抓取数据的过程
- 模拟:
- 浏览器本身就是一个纯天然的爬虫工具,爬虫相关的模块都是基于浏览器为基础开发出来的。
- 注意:日后只要是你的爬虫程序没有爬取到你想要的数据,只有一个原因:
- 抓取:
- 抓取网页数据分两种情况:
- 将一个页面所有的数据抓取到
- 将页面中局部的数据抓取到
- 爬虫在应用场景的分类
- 通用爬虫:
- 将一个页面中所有的数据获取。
- 大部分的搜索引擎中应用比较多。
- 聚焦爬虫
- 将页面中局部的指定的数据进行提取/抓取
- 注意:聚焦爬虫一定是建立在通用爬虫的基础之上实现。
- 功能爬虫
- 通过浏览器或者app自动化的操作,实现相关的网页或者app自动化的操作。代替人工在网页或者手机软件中自动执行相关的行为动作。
- 批量点赞,批量评论,刷单,秒杀…..
- 增量式爬虫
- 用来监测网站数据更新的情况。以便爬取网站最新更新出来的数据!
- 分布式爬虫
- 可以对网站所有的资源使用分布式机群进行分布和联合的数据爬取
- 爬虫的矛与盾
- 反爬机制:对应门户网站,网站可以指定相关的机制阻止爬虫对其网站数据的采集
- 反反爬策略:对应爬虫程序,爬虫可以制定相关的策略将网站的反爬机制破解,从而爬取到指定的数据
- 盗亦有道的君子协议robots
- Robots协议(也称为爬虫协议、机器人协议等)的全称是“网络爬虫排除标准”(Robots ExclusionProtocol),网站通过Robots协议告诉搜索引擎哪些页面可以抓取,哪些页面不能抓取.
- 注意,这个协议的存在更多的是需要网络爬虫去遵守,而起不到防止爬虫的功能。
爬虫合法性探究
- **爬虫作为一种计算机技术就决定了它的中立性,因此爬虫本身在法律上并不被禁止,但是利用爬虫技术获取数据这一行为是具有违法甚至是犯罪的风险的。**所谓具体问题具体分析,正如水果刀本身在法律上并不被禁止使用,但是用来捅人,就不被法律所容忍了。
- 或者我们可以这么理解:爬虫是用来批量获得网页上的公开信息的,也就是前端显示的数据信息。因此,既然本身就是公开信息,其实就像浏览器一样,浏览器解析并显示了页面内容,爬虫也是一样,只不过爬虫会批量下载而已,所以是合法的。不合法的情况就是配合爬虫,利用黑客技术攻击网站后台,窃取后台数据(比如用户数据等)。
- 举个例子:像谷歌这样的搜索引擎爬虫,每隔几天对全网的网页扫一遍,供大家查阅,各个被扫的网站大都很开心。这种就被定义为“善意爬虫”。但是像抢票软件这样的爬虫,对着 12306 每秒钟恨不得撸几万次,铁总并不觉得很开心,这种就被定义为“恶意爬虫”。
- 爬虫所带来风险主要体现在以下3个方面:
- 1、违反网站意愿,例如网站采取反爬措施后,强行突破其反爬措施;
- 2、爬虫干扰了被访问网站的正常运营;
- 3、爬虫抓取了受到法律保护的特定类型的数据或信息。
- 那么作为爬虫开发者,如何在使用爬虫时避免进局子的厄运呢?
- 1、严格遵守网站设置的robots协议;
- 2、在规避反爬虫措施的同时,需要优化自己的代码,避免干扰被访问网站的正常运行;
- 3、在使用、传播抓取到的信息时,应审查所抓取的内容,如发现属于用户的个人信息、隐私或者他人的商业秘密的,应及时停止并删除。
- 总结:
- 可以说在我们身边的网络上已经密密麻麻爬满了各种网络爬虫,它们善恶不同,各怀心思。而越是每个人切身利益所在的地方,就越是爬满了爬虫。**所以爬虫是趋利的,它们永远会向有利益的地方爬行。**技术本身是无罪的,问题往往出在人无限的欲望上。因此爬虫开发者的道德自持和企业经营者的良知才是避免触碰法律底线的根本所在。
requests基础操作
- 基本介绍
- requests就是爬虫中一个基于网络请求的模块。
- 作用:模拟浏览器上网的。
- urllib模块就是一个老版的requests模块,现在没人用urllib
- 环境安装
- 编码流程
- 指定url(好比打开浏览器输入网址)
- 发起请求(好比是按下回车)
- 获取响应数据(从指定url中爬取到的数据)
- 持久化存储
- 案例应用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import requests
url = 'https://www.sogou.com/'
response = requests.get(url=url)
page_text = response.text
with open('./sogou.html','w') as fp: fp.write(page_text) print('数据爬取存储成功!')
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import requests
keyword = input('请输入关键字:')
pram = { 'query':keyword, }
url = 'https://www.sogou.com/web'
response = requests.get(url=url,params=pram)
page_text = response.text
fileName = keyword + '.html' with open(fileName,'w') as fp: fp.write(page_text)
|
- 分析该网站的反爬机制:
- 从爬取到的内容中提取到了一个关键信息:网站检测到了异常的访问请求
- 异常的访问请求:通过程序发起的请求
- 正常访问请求:通过浏览器发起的请求
- 网站如何可以监测请求是不是通过浏览器发起的呢?
- 是通过请求的一个头信息:user-agent
- user-agent:请求载体的身份标识
- 破解方式(UA伪装):伪装请求载体的身份标识
- 该反爬机制是一种最常见最通用的,也就是说绝大数网站都会携带该反爬机制,因此日后写爬虫程序,默认带上UA伪装操作。
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import requests
keyword = input('请输入关键字:')
pram = { 'query':keyword, }
url = 'https://www.sogou.com/web'
head = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' }
response = requests.get(url=url,params=pram,headers=head)
page_text = response.text
fileName = keyword + '.html' with open(fileName,'w') as fp: fp.write(page_text)
|
- 豆瓣电影
- 特指,不是通过浏览器地址栏的请求请求到的数据,就是动态加载数据。同理,动态加载数据一定是通过其他的请求请求到的。
- 如何获取动态加载数据?
- 基于抓包工具进行全局搜索
- 鼠标点击任意的数据包,然后按下cotrl+f打开全局搜索框,搜索局部你想要的数据,即可定位到包含搜索数据的指定数据包。
- 从指定数据包中就可以提取出:
- url:https://movie.douban.com/j/chart/top_list
- 请求方式:get
- 请求参数:type=13&interval_id=100%3A90&action=&start=0&limit=1
-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import requests head = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' } pram = { "type": "13", "interval_id": "100:90", "action": "", "start": "0", "limit": "20", } url = 'https://movie.douban.com/j/chart/top_list' response = requests.get(url=url,headers=head,params=pram)
page_text = response.json() fp = open('./douban.txt','w') for dic in page_text: title = dic['title'] score = dic['score'] fp.write(title+':'+score+'\n') print(title,'爬虫保存成功!')
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import requests head = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36' }
data = { "cname": "", "pid": "", "keyword": "天津", "pageIndex": "1", "pageSize": "10", }
url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword'
response = requests.post(url=url,headers=head,data=data)
page_text = response.json() for dic in page_text['Table1']: name = dic['storeName'] addr = dic['addressDetail'] print(name,addr)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import requests
url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById'
data = { 'id':'d601af664b5940029601d6d0a05be321' }
headers = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36X-Requested-With: XMLHttpRequest' }
response = requests.post(url=url,data=data,headers=headers)
json_data = response.json()
print(json_data['epsName'],json_data['legalPerson'],json_data['productSn'])
|
- 再次对另一家企业的企业详情数据进行分析
- 定位到了动态加载数据对应的数据包
- 在该数据包中可以提取到url,请求方式和请求参数,对比发现,不同企业的详情数据的数据包请方式和url是一样的,只有请求参数id的值不一样。
- 结论:不同企业的企业详情数据对应的数据包只有id的参数不同剩下都一样。
- 结果:如果我们可以批量获取多家企业的id值,就可以批量获取多家企业的企业详情数据。
- 如何批量获取多家企业的id值?
- id通常表示一组数据的唯一标识。联想到企业的名称也会作为企业的唯一标识,那么会不会企业的id和企业的名称在页面中是绑定在一起的呢?
- 测试:在首页通过企业名称找到企业的id
- 通过抓包工具的分析,首页中企业的名称等信息也是动态加载数据。
- 捕获动态加载数据。定位到指定的数据包,从数据包的响应数据中发现了不同企业的id,就可以将不同企业的id取到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import requests
headers = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36X-Requested-With: XMLHttpRequest' } main_url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList' m_data = { "on": "true", "page": "1", "pageSize": "15", "productName": "", "conditionType": "1", "applyname": "", "applysn": "", } m_response = requests.post(url=main_url,headers=headers,data=m_data) json_data = m_response.json() for dic in json_data['list']: _id = dic['ID'] print(_id)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import requests
headers = { 'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36X-Requested-With: XMLHttpRequest' } main_url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsList' m_data = { "on": "true", "page": "1", "pageSize": "15", "productName": "", "conditionType": "1", "applyname": "", "applysn": "", } m_response = requests.post(url=main_url,headers=headers,data=m_data) json_data = m_response.json() ids = [] for dic in json_data['list']: _id = dic['ID'] ids.append(_id)
for _id in ids: url = 'http://scxk.nmpa.gov.cn:81/xk/itownet/portalAction.do?method=getXkzsById' data = { 'id':_id } response = requests.post(url=url,data=data,headers=headers) json_data = response.json() print(json_data['epsName'],json_data['legalPerson'],json_data['productSn'])
|