V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
1024dada
V2EX  ›  Python

爬虫入门教程— jupyter 与 requests 的初步使用

  •  
  •   1024dada · 2018-12-19 12:24:16 +08:00 · 2109 次点击
    这是一个创建于 2167 天前的主题,其中的信息可能已经有所发展或是发生改变。

    jupyter 是一个简易的,方便的写 Python 代码的工具包,requests 是 Python 里非常好用的用来发送 http 请求的包。

    开始学习本教程之前,请确保你已经安装了 Python,并且安装了 Python 包 jupyter 和 requests 了。如果没有,那请参照以下教程进行安装:

    爬虫入门教程⑤— 安装 Python 爬虫入门教程⑥— 安装爬虫常用工具包。

    1. jupyter 的简单使用 老规矩:Windows 键+X 键选择 命令提示符。 打开了命令提示符,那么我们输入命令: jupyter notebook 回车。 接着你的浏览器会自动打开下面的界面: 注: 如果没有自动打开浏览器却显示了一个网址在窗口里面,那么是你电脑没有设置默认浏览器或者默认浏览器设置错误导致的; 如果浏览器打开了网页却不显示任何东西,无法正常使用,请检查你的浏览器的版本是否比较陈旧,推荐使用 Firefox、Chrome、QQ 浏览器等使用非 IE 内核或高等级 IE 内核的浏览器。

    接着我们点击网页右边的 new,选择 Python3。(我的 jupyter 多了个 Python2 的选项,那是因为我自己给 jupyter 配置了 Python2,默认情况下,只有你当前的 Python 版本的文件选项。)

    选择了创建文件之后,浏览器打开了一个新的界面,这就是我们的代码编辑界面啦,从此以后就可以开开心心写代码了。 我们在下面的 In [ ]:那里输入我们的第一个程序的第一条语句: print("Hello World") 然后点击画面上方的 Run 按钮,就运行我们的程序啦。效果如图:

    Requests: HTTP for Humans 这是 requests 的 slogan。非常简单明了,我觉得翻译成中文大概是:给人使用的 HTPP 请求库。 根据我个人经验来说,看到过很多初学者(也包括曾经的我),都跟着网上很老的爬虫教程,使用 urllib、urllib2 来发起请求。这样的结果是什么?不仅写代码效率非常低下,而且代码量比 requests 多得多,同时代码也难以理解。 这几个过时的库一点也不友好,简直不像是给人使用的。 所以从遇到 requests 的第一天起,我就永远地抛弃了 urllib 之类的库了。

    requests 的作者,是一位非常帅气的摄影师小哥。目前 requests 在 GitHub 上已经获得了 32062 个 Star。

    下面我们来学习 requests 的基本使用。

    1. import requests 并发起一个请求 我们在 jupyter 的新的一个输入里面,键入下面的代码并点击运行:

    import requests
    print(requests.get("https://www.baidu.com"))
    注意:括号都是英文的括号哦 运行结果:

    import requests: 代码文件里面引入 requests 这个包以便后面代码的使用 print(requests.get("https://www.baidu.com")):用 requests 向百度首页发起一个 get 请求,并打印出请求的结果(response 对象)。 这就已经完成了我们使用浏览器打开百度首页的过程了。那为什么我们没看到网页也没看到 html 呢?我们把代码改成这样再运行一次:

    import requests response = requests.get("https://www.baidu.com") print(response.status_code) print(response.content) 运行结果:

    第一行的 200,是我们这个请求的 HTTP 状态码,200 表示请求成功,关于状态码前面已经讲解过了:爬虫入门教程③— 必备知识基础(二)HTTP 请求简介。

    第二行开始就是输出的我们获取到的百度首页的 HTML 代码的二进制字符串,b'xxxxx'表示这个字符串是二进制的。 那我们怎么把二进制结果改成我们看得懂的中文结果呢?我们只需要对响应的 content(二进制)进行一次解码,常见的解码方式有 gbk,utf-8。 Windows 文件用的是 gbk 编码,有一些比较古老的网页也是用的 gbk 编码。现在大部分的网页都是用的 utf-8 的编码了。 我们怎么知道网页用的哪个编码呢?一般是看 meta 信息里面 charset 的值:

    当然也可以猜,不报错,不乱码,那就对了。

    于是我们在输出二进制响应后面加上.decode('utf-8'),把二进制字符转换成字符串:

    import requests response = requests.get("https://www.baidu.com") print(response.status_code) print(response.content.decode('utf-8')) 输出如下:

    现在就能看懂了,我们成功打开了百度的首页! 是的,requests 发起一个请求就是这么简单。

    要发起 post 请求,也同样简单

    import requests form = {'username': 'admin','password': 'admin123456'} response = requests.post("https://www.baidu.com", data=form) print(response.content.decode('utf-8')) 这就向百度首页,发起了一个 post 请求,并且带上了两个参数,参数名是 username 和 password,值是 admin 和 admin123456。post 请求我们一般用于对网页发送数据,比如登录,发送图片、文件等等。如果请求方式弄错了,很可能得不到正确的响应的哦。

    1. requests.session 的使用 这里要介绍一下 cookie:

    Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

    cookie 就相当于一个令牌,你拿着它去访问网站,网站就能辨别你是谁了。所以如果你登录了,你去访问其他需要登录的网页,都可以直接访问,因为浏览器在你访问的时候,默认会带上 cookie。cookie 的添加、删除、更新是在服务器返回的响应里获取到的。

    requests.get() 是发送请求常用的一个办法。它不能做到的是对 cookie 的持久化: 上一个请求获取到的 cookie,没办法简单地传递到下一个请求去,这样两个 requests.get()请求之间没有办法产生联系。如果是对于需要登录的网站来说,这是毁灭性的,我们会一直卡在登录界面。 下面要引入的就是 requests 的 session。它能够自动管理 cookie,也能够进行 cookie 的持久化。用法也很简单:

    import requests http_session = requests.session() response = http_session.get("https://www.baidu.com") print(response.content.decode('utf-8')) 我们定义了一个 http_session 用来作为我们的 session。然后我们使用这个 http_seesion 发出的每个请求,都会自动带上 cookie,也会自动处理网站服务器返回的对 cookie 的操作。 这些过程对我们不可见,而我们只需要使用就好了!简直完美!

    1. 把从浏览器获取到的 cookie 添加到 session 里来绕过登录 注:此小节为进阶教程,不理解可暂时跳过。

    首先补充一下 cookie 的知识:

    原因: http 请求是无状态的,也就是说,你的每一次请求,网站服务器都会认识是一次新的请求。

    问题:既然每一次请求都是新的请求,那么网站识别用户就遇到困难了:一个网站需要服务于多个用户,每个用户的需要呈现的内容可能是不同的。如果每次请求都是全新的,服务器会不知道是谁发过来的,进而就可能造成一个混乱的局面,把 A 的消息发给了 B,C 的邮件给了 A 等等。

    解决方案:服务器如果需要识别你的身份,那它就给你发送一个或多个 cookie(如果不需要对你进行特异性识别,那就没必要设置 cookie 了),之后你的每个请求默认会带上服务器设置的 cookie(浏览器自动处理)。由于服务器给每个用户的分配的 cookie 的值是不同的,那服务器就可以轻松地通过 cookie 的值来识别用户了。

    拓展:既然服务器是通过 cookie 这个令牌识别你是谁的,那么只要你的请求带上了任意一个人的 cookie 去访问服务器,那么服务器就会认为你就是那个人。所以在以前有中间人攻击这个事情,黑客就是通过拦截你的请求,找到你的 cookie,自己伪装成你,然后帮他发广告或者是进行一些其他的危险操作以获得利润。

    如果我们需要爬取一个需要登录的网站,但是他的登录流程非常麻烦,甚至需要输入验证码。我们有没有什么比较轻便的办法来解决这个问题呢? 当然有:我们在浏览器上登录了,然后把浏览器上的网站发送给你的 cookie,按照格式添加到我们的 session 里面,那么我们就无需登录,成功伪装成了浏览器里面的自己的账号了,进而可以直接进行爬取了(每个请求带上 cookie,服务器就会认为我们是已经登录过了)。

    怎么获取浏览器的 cookie 呢? F12 打开调试模式,然后选中 NetWork(网络)。接着鼠标点到网页上去,按 F5 刷新界面。我们马上可以看到在调试窗口里面的列表有一个接一个的请求出现了,我们找到第一个请求(通常是第一个,具体请看请求的网址),点击一下,就显示出了这个请求的具体信息了。 接着再找到 Request Header 里面的 Cookie:

    在我的截图里面,百度给我发送了非常多的 cookie,你可能没这么多,但是也不影响,毕竟这只是个示例。

    接着我们把所有的 cookie 复制下来。 每一条 cookie 是以;隔开的,所以我们先以;把这些 cookies 分开,分割为一条条的 cookie。 对于每条 cookie 我们再以第一个=把一条 cookie 分为 name 和 value 两个部分。 然后我们把这些 key-value 的数据,添加到一个 dict 里面 最后把 cookie 添加到 http_session 的 cookies 里面。 举个例子,复制下来的 cookies 字符串为 "sessionid=124586245;name=pikaqiu;FDS=fdsa=okok;how=areyou" 首先我们以;切割这个字符串得到了下面这几条 cookie

    "sessionid=124586245" "name=pikaqiu" "FDS=fdsa=okok" "how=areyou" 然后我们再把这几条 cookie 转换成 requests 能够接受的格式:

    cookies = { 'sessionid': '124586245', "name": "pikaqiu", "FDS": "fdsa=okok", "how": "areyou", } 最后再把这个 cookie 添加到 requests 提供的 http_session 里面,之后这个 session 就会自动为我们处理 cookie 了,包括每个请求发送 cookie,修改和删除 cookie 的信息。

    下面以上图的百度举个例子,下面就是采用了我自己的 cookie 访问百度的例子:

    import requests http_session = requests.session() cookies = {'BAIDUID': 'CC97B75E17BC78:FG=1', 'BIDUPSID': 'CC97B75E17FE0BEEBC78', 'PSTM': '15700', 'BDSFRCVID': 'th-sJeC626F0ZTQA', 'H_BDCLCKID_SF': 'tJPjVC0yt', 'ispeed_lsm': '2', 'H_PS_645EC': '00e6qFET6oh4QC9Q', } # 为了减少篇幅,我删掉了后面的几个 cookie,你们可不能偷懒哦~ requests.utils.add_dict_to_cookiejar( http_session.cookies, cookies) response = http_session.get("https://www.baidu.com") print(response.content.decode('utf-8')) 通过把浏览器的 cookie 添加到程序里面,然后用程序来进行访问,我们就可以节约用程序登录的步骤,专心进行我们其他的操作了。这个办法同样适用于一些不需要登录,但是对 cookie 有要求的网站。

    附上 requests 的文档: 中文文档:快速上手 — Requests 文档 英文文档:Requests: HTTP for Humans — Requests documentation 本节到此结束,下一节会是关于如何从 HTML 字符串里面提取出我们需要的内容的教程。感谢观看。

    更多教程尽在每日答答官网: https://1024dada.com/?channel=v2ex

    7 条回复    2018-12-19 19:54:28 +08:00
    iiusky
        1
    iiusky  
       2018-12-19 12:44:09 +08:00
    这排版。。????确定是推广么?
    xiaoheijw
        2
    xiaoheijw  
       2018-12-19 13:38:01 +08:00
    requests 的作者是程序员好不。神 tm 摄影师
    beforeuwait
        3
    beforeuwait  
       2018-12-19 13:48:02 +08:00
    字多不看
    holajamc
        4
    holajamc  
       2018-12-19 14:20:16 +08:00
    @xiaoheijw 除了程序员,还有摄影师、音乐家、演讲者… ....
    www5070504
        5
    www5070504  
       2018-12-19 14:24:16 +08:00
    看见这种推广有点想喷
    jatesun
        6
    jatesun  
       2018-12-19 18:20:03 +08:00
    我 tm...
    Kobayashi
        7
    Kobayashi  
       2018-12-19 19:54:28 +08:00 via Android
    @holajamc 怪不得他喜欢在 documentation 里塞没用的装饰图片。跟文档内容完全不相关还浪费流量,用 sphinx 生成文档时还没办法通过 sphinx 配置参数来去掉。他 pipenv 的文档也是这么玩儿。生成 dash 离线文档都要 beautiful 处理一边。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1235 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 17:36 · PVG 01:36 · LAX 09:36 · JFK 12:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.