总纲
程序入门两步骤,请求和响应,服务器响应之后,传回数据,然后我们对返回的数据进行解析成bs格式,然后进行提取。
最简单的请求格式如下:
import requests
url = ''
response = requests.get(url)
工具Network
Network
能够记录浏览器的所有请求
最常用的是:ALL(查看全部),XHR(仅查看XHR),Doc(Document,第0个请求一般在这里)
有时候也会看看:Img(仅查看图片)/Media(仅查看媒体文件)/Other(其他)
最后,JS和CSS,则是前端代码,负责发起请求和页面实现
Font是文字的字体;而理解WS和Manifest,需要网络编程的知识,
如下图network的属性
network里面的所有内容组成Elements ,Elements组成我们日常所见的万紫千红的网页
最常用的是XHR
和Doc
我们能在Doc
里找到一个网页的源代码,而在网页源代码里找不到的信息,
通常你都能在XHR
里找到。有它的存在,人们不必刷新/跳转网页,即可加载新的内容。在今天,已经学过“同步/异步”概念的你,也可以说XHR
帮我们实现了异步请求。
而数据究竟是藏身何处,方案如下:需要详细了解何时使用这个功能
总结:
使用Network里面的Doc和XHR ,我们能够查看到网页的源代码,从而在源代码里面提取到我们想要的信息
如果Doc里面没有我们想要的数据,就需要去到XHR里面去寻找
XHR的详细操作见第5章
解析与提取(一)即Doc
情况一:数据藏匿于网页源代码,我们自有一条完整的“爬虫四步”链
使用最重要的库叫BeautifulSoup,它能提供一套完整的数据解析、数据提取解决方案。
标准代码如下:(两种方法)
import requests
# 引用requests库
from bs4 import BeautifulSoup
# 引用BeautifulSoup库
res_foods = requests.get('http://www.xiachufang.com/explore/')
# 获取数据
bs_foods = BeautifulSoup(res_foods.text,'html.parser')
# 解析数据
tag_name = bs_foods.find_all('p',class_='name')
# 查找包含菜名和URL的<p>标签
tag_ingredients = bs_foods.find_all('p',class_='ing ellipsis')
# 查找包含食材的<p>标签
list_all = []
# 创建一个空列表,用于存储信息
for x in range(len(tag_name)):
# 启动一个循环,次数等于菜名的数量
list_food = [tag_name[x].text[18:-15],tag_name[x].find('a')['href'],tag_ingredients[x].text[1:-1]]
# 提取信息,封装为列表
list_all.append(list_food)
# 将信息添加进list_all
print(list_all)
# 打印
# 以下是另外一种解法
list_foods = bs_foods.find_all('div',class_='info pure-u')
# 查找最小父级标签
list_all = []
# 创建一个空列表,用于存储信息
for food in list_foods:
tag_a = food.find('a')
# 提取第0个父级标签中的<a>标签
name = tag_a.text[18:-15]
# 菜名,使用[18:-15]切掉了多余的信息
URL = 'http://www.xiachufang.com'+tag_a['href']
# 获取URL
tag_p = food.find('p',class_='ing ellipsis')
# 提取第0个父级标签中的<p>标签
ingredients = tag_p.text[1:-1]
# 食材,使用[1:-1]切掉了多余的信息
list_all.append([name,URL,ingredients])
# 将菜名、URL、食材,封装为列表,添加进list_all
print(list_all)
# 打印
res_foods.text 这里,为什么变成了text,代码第8行
程序的另外一种写法
关于解码的提示:当response.text
自动解码出问题,不要犹豫,自己动手使用response.encoding=''
来对编码进行修改
解析与提取(二)即XHR
XHR所传输的数据,最重要的一种是用json格式写成的,json的数据类型是“文本”,在Python语言当中,我们把它称为字符串
json和html一样,这种数据能够有组织地存储大量内容,我们能够非常轻易地将json格式的数据转化为列表/字典,也能将字典/列表转为json格式的数据
如何提取XHR中的内容
Doc中提取内容和XHR中提取内容的区别
更厉害的请求: 即给requests.get()里面加参数
params,可以让我们带着参数来请求数据:我想要第几页?我想要搜索的关键词?我想要多少个数据?
url_2 = 'https://…'
params = {}
# 定义url和params
response = requests.get(url,headers=headers,params=params,cookies=cookies)
# 带着cookies重新发起请求
headers,请求头。它告诉服务器,我的设备/浏览器是什么?我从哪个页面而来?
headers = {'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'}
#user-agent这里标记了请求是从什么设备上,什么浏览器上发出的
response = requests.get(url,headers=headers,params=params,cookies=cookies)
cookies(用于需要登录才能获取数据的网站)里面携带了浏览器访问网站时,留在服务器的账号密码以及在网站上的操作历史(比如购物车),以及缓存等,访问网站时带上cookie可以免去密码
post请求(用于初次登录获取cookies), get请求之外,还存在着另一种请求方式——post。post区别于get的是:get是明文显示参数,post是非明文显示参数。学会post,你又有两个参数可用:在里,我们使用data来传递参数,其用法和params非常相像。
import requests
# 定义url_1,headers和data
url_1 = 'https://…'
headers = {'user-agent':''}
data = {}
login_in = requests.post(url,headers=headers,data=data)
cookies = login_in.cookies
# 完成登录,获取cookies
url_2 = 'https://…'
params = {}
# 定义url和params
response = requests.get(url,headers=headers,params=params,cookies=cookies)
# 带着cookies重新发起请求
存储-csv,excel 数据库-MySQL和MongoDB
多协程-gevent
爬虫框架-Scrapy
selenium-自动操作浏览器
爬虫进阶
爬虫进阶1-除了BeautifulSoup解析、Selenium的自带解析库,我们还需要学习re模块(重要),xpath/lxml等
爬虫进阶2-数据库存储,MySQL和MongoDB这两个库开始学起,它们一个是关系型数据库的典型代表,一个是非关系型数据库的典型代表
爬虫进阶3-数据可视化Pandas/Matplotlib/Numpy/Scikit-Learn/
Scipy
爬虫进阶4-分布式爬虫
爬虫进阶5-更多框架
使用Scrapy模拟登录、存储数据库、使用HTTP代理、分布式爬虫,先去更深入地学习、了解Scrapy框架。然后再了解一些其他的优秀框架,如:PySpider
爬虫进阶6-实战训练
爬虫训练的核心目的-如何用最快最好的工具组合来达成爬到数据的目标
上述的模块/库/框架并不是那样重要,因为它们都是易于掌握的工具。对于一个爬虫工程师来说最重要的,是达成目标的思维。
相信你已经能感受到,在我们所有的项目型关卡里,都遵循着这三个核心步骤:确认目标、分析过程和代码实现(对于复杂项目,也要去做代码封装)。
其中,难度最大的不是代码实现,也不是代码封装,而是:确认一个合理的目标,分析这个目标如何实现,设计这些工具模块如何组合应用。
我们所学习的爬虫四步:获取数据、解析数据、提取数据和存储数据,都服务于“分析过程”这一步。
我要的数据在哪?怎么拿到数据?怎么更快地拿到数据?怎么更好地存储数据……这个,都属于“达成目标的思维”。
获取这种思维,需要大量的项目实操练习。
所以我想推荐你:完成我所提供的所有项目练习;多读一读,编程前辈们的博客、github主页学习案例;同时,探索更多的项目实操,丰富自己的爬虫经验。
在未来,如果我再设计更进阶的爬虫课程,教授正则、进程、分布式……的知识,也一定会将大量项目实操作为主线。
反爬虫应对策略汇总
①限制请求头:即Request Headers,那我们就去填写user-agent
声明自己的身份,有时还要去填写origin
和referer
声明请求的来源
②限制登录,不登录就不给你访问,我们就用cookies
和session
的知识去模拟登录
③做一些复杂的交互,比如设置“验证码”来阻拦登录:解决方案一般有二:我们用Selenium
去手动输入验证码;我们用一些图像处理的库自动识别验证码比如 tesserocr/pytesserart/pillow
④会做IP限制,解决方案有二:使用time.sleep()来对爬虫的速度进行限制;建立IP代理池(你可以在网络上搜索可用的IP代理),一个IP不能用了就换一个用。
import requests
url = 'https://…'
proxies = {'http':'http://…'}
# ip地址
response = requests.get(url,proxies=proxies)
学习总结和人生道理
爬虫最重要的事情
确认目标-分析过程-先面向过程一行行实现代码-代码封装
在这,最重要的是确认目标,最难的是分析过程。写代码,不过是水到渠成的事,最重要的事情往往不是最难的事情,人生哲理,先确定最重要的事情,即道,然后才做最难的事情,即术。所以每日优鲜的活动天花乱坠,营销天花乱坠,其实效果并不好,没有抓到本质问题
说是理论,最近一些年,除了技术之外,我浸心于一门叫做“认知心理学”的学科。它所研究的,是人的认知过程。读起来,实在是有趣极了。
何解决问题的。最后,得出的一个关键结论是,人类最有效地解决问题方式,是“目标-手段分析法”。
确认目标,一层一层地分解,大问题变一组小问题,每一个小问题都有实现的手段,然后去做就好。事情仿佛就是这样简单。但事情不是这样简单。
我不知道你是否还记得第4关的样子。那时,你刚刚学会BeautifulSoup,你接到一个需求:爬取周杰伦的歌曲信息。
你确认目标-分析过程-然后代码实现。突然,事情的结果却在预期之外——没拿到想要的数据。
你并不会因此而感到慌张,为什么?
因为我们的每一步过程,都是非常清晰地推理得来。我们能很容易定位到问题——一步步反推回去就好。
是提取错了吗?检查,不是。是解析错了吗?检查,不是。那定是获取数据错了。我们去重新分析过程:去学习新的知识——XHR,去查文档——解析json数据。
同理,当我们所做的事情不及预期,我们可以检查是执行错了吗?不是,那是手段错了吗?如果还不是,那就需要思考,是不是目标制定有问题。
同样的事情发生在我的身上。当我在写这个爬虫关卡,我会思考一个目标:我把这些关卡做到什么程度,你会满意?
然后是分析手段:每一个关卡,应该教什么内容,才能最终实现这个目标。
继续分析手段:每一个关卡,应该怎么教,才能教好我想教的内容……
一层层拆解,环环相扣,没有一个信息多余,没有一个信息欠缺,最终它们构成你眼前的这副模样。
如果你告诉我哪里学得不好,那么我将会反推上述是哪一步做得不好,再将它修正掉。这就是我今日工作的方式。我相信最终,我和我的团队能设计出这个世界上最好的教育解决方案。
坚持这样思考,我相信在你的生活里,一切事物都可以是明确而可实现的。即便出了问题,也能清晰地溯源。
你逢山开路,你从不慌张。以上,就是我想要告诉你所有的事情。
在最后,理论上来说一封书信的末尾应是落款。
段:每一个关卡,应该教什么内容,才能最终实现这个目标。
继续分析手段:每一个关卡,应该怎么教,才能教好我想教的内容……
一层层拆解,环环相扣,没有一个信息多余,没有一个信息欠缺,最终它们构成你眼前的这副模样。
如果你告诉我哪里学得不好,那么我将会反推上述是哪一步做得不好,再将它修正掉。这就是我今日工作的方式。我相信最终,我和我的团队能设计出这个世界上最好的教育解决方案。
坚持这样思考,我相信在你的生活里,一切事物都可以是明确而可实现的。即便出了问题,也能清晰地溯源。
你逢山开路,你从不慌张。以上,就是我想要告诉你所有的事情。
在最后,理论上来说一封书信的末尾应是落款。
但我不肯落款自己的名姓——因为风变编程发展至今,已经远不是我一个人就能完成所有的工作。你所见的这些关卡,背后有许许多多的人在为它工作,我怎忍独自贪功。