Day 17:专案03 - PTT 八卦版爬虫02 | session、post

昨天教到使用cookie让服务器记得我们曾经做过哪些事,但缺点就是每次Request都要加上cookie才行,非常麻烦。今天就来讲怎麽使用session解决这个问题吧~

但在讲session之前,我们要先知道为什麽每次Request都要加上cookie?

网路的世界

现在网路通讯大多采用HTTP协定,而HTTP是一个「无状态」的协定。什麽意思呢?就是每一次 request 都是一个「独立的」request,彼此之间不会有任何纪录和关联。所以 Server 那边也不会保存任何状态,每一次 request 都视为一个新的 request。

换句话说,你可以把服务器想成是一个丧失记忆能力的人,每一次你去找他的时候,他都当作是第一次见到你,完全不记得你以前曾经找过他。

就会发生这种事...

这就是每次Request都要加上cookie的原因,解决方法就是用刚才提到的session~

什麽是session?

session的英文意思是 持续一段时间的状态,是一个让HTTP协定的request变成「有状态」的机制,有状态之後才能完成很多功能,像是:登入系统、购物车等等。

要实现session机制可以利用许多方法,其中一种就是用cookie。

还记得昨天这张图吗? 利用cookie让使用者和服务器间保有状态的这个机制(或流程)就叫做session。

想更进一步了解cookie和session的观念,可以参考这篇文章:
白话 Session 与 Cookie:从经营杂货店开始

如何使用session?

Requests内建session物件,使用session()函数开启一段session,便会自动记录session期间所存的cookie,让服务器保留这段session的状态。

rs = requests.session()

刚才我们每次request都要送cookie过去,非常的麻烦,所以才改成用session。但这边出现一个问题,我们该怎麽让服务器对使用者设定cookie呢? 这就要回头复习刚刚进八卦板的流程了。

  1. 先进入 "询问你是否满18岁" 的画面
  2. 然後你按了 "我同意"
  3. 浏览器存下 "over18的cookie"
  4. 进入文章列表

先打开 F12>>Network,接着完成上述的流程後,应该会看到一个名称叫over18的request,点开来後可以观察到request的网址和方法,滑到最下面可以看到他传了什麽资料。

可以看到request方法不是刚才用的GET而是POST,所以接下来就要讲GET跟POST到底有什麽不同?

GET vs. POST

GET和POST都是http协定下所规范的请求方法(request methods),两者经常用於向服务器请求资源,不过两者在参数(资料)的传送上采用不同的方法。

GET

将资料全部写在URL中,就像你写明信片一样,传递上较不安全。

GET加上参数的格式:https://www.example.com/index.html?key1=value1&key2=value2

POST

将资料写在内部,就像你写信然後装进信封袋一样,传递上比较安全且传递的资讯可以比较多。

所以在点下 "我同意" 按钮的时候,事实上就是向PTT的服务器发出一个POST的请求,并带上fromyes这两个资料,服务器接收到这个POST请求後,就会回应要求浏览器设定over18=1的cookie了!

仔细看刚才over18的request,在Response Headers有一个栏位是set-cookie,就是在设定cookie。

程序实作

既然原理都知道了,接下来就让程序模仿使用者做一模一样的事情就好啦!

import requests
from bs4 import BeautifulSoup

# post要传的资料
payload = {
    'from': '/bbs/Gossiping/index.html',
    'yes': 'yes'
}

# 用session纪录此次使用的cookie
rs = requests.session()
# post传递资料
response = rs.post("https://www.ptt.cc/ask/over18", data=payload)
# 再get一次PTT八卦板首页
response = rs.get("https://www.ptt.cc/bbs/Gossiping/index.html")
print(response.status_code)

root = BeautifulSoup(response.text, "html.parser")
links = root.find_all("div", class_="title")    # 文章标题
for link in links:
    print(link.text.strip())  # strip()用来删除文字前面和後面多余的空白

执行结果:

结果跟昨天一样,但会发现这次在GET的时候就不需要带上cookie了,因为session会自动帮你带上。

所以,好session,不用吗?

最後再提一下写爬虫时应该具备的观念。

爬虫重要观念

>>> 让程序模拟真人的行为 <<<

因为爬虫会造成服务器的负担,所以大部分网站都不欢迎别人来爬他们的网站,因此多数网站都会设下许多障碍阻止爬虫。

想当然,魔高一尺道高一丈,身为一个工程师,就要想尽办法让你的程序看起来像是真人,以骗过服务器的眼睛。

小结

今天提到了利用session的机制,让http协定下的request保有状态,以及使用POST方法让服务器对浏览器设定cookie,最後提到爬虫的重要观念。今天多数的内容都满抽象的,但对爬虫来说都是非常重要的观念,希望大家看完今天的文章後可以好好吸收,之後在爬虫会帮助你更加顺利。

我原本以为我已经很懂cookie和session的概念,但为了写这篇文章去查一下资料才发现原来有部分的观念搞错了! 後来把这些资料全部读完吸收後才来写文章,所以这篇文章的观念应该都是正确的,不用担心啦~

这也是为什麽我常常鼓励人要写文章的原因,因为有时候自以为正确的观念,在教人时才发现自己根本就没有搞清楚。透过写文章的方式,便能够更清楚显示出自己的弱点在哪里

好啦,题外话就讲到这,现在已经可以抓到文章列表了,所以明天就来讲怎麽进到文章中,抓下标题、作者等资讯吧!


如果喜欢这系列文章麻烦帮我按Like加订阅,你的支持是我创作最大的动力~

本系列文章以及范例程序码都同步更新在GitHub上,後续会持续的更新,如果喜欢也麻烦帮我按个星星吧~

有任何问题或建议,都欢迎在底下留言区提出,还请大家多多指教。


<<:  【第八天 - Flutter Provider 架构教学】

>>:  [Day07]打造专业稽核形象

虹语岚访仲夏夜-0(悲伤的blue)

台北,又变了呢,记得很久前,才在盖的101到现在,烟火都不知道放了几遍,他一定没有在看那些,如果有机...

Day-12: ORM系虾米捏?

ORM (Object-relational mapping ) 是一种对映射关联式资料与物件资料的...

Day 7【钱包登入区 - Login Button】Kitten or Ice Cream?

【前言】 先来回顾一下 Day2 Project 分析的使用者流程,今天先来做第一步的 「登入按钮...

[Flutter ] Django 为资料库,以 FutureBuilder + http 抓取

Free fake API 为资料库,以 FutureBuilder + http 抓取 为Flut...

30天学会C语言: Day 0-第一篇不免俗的要来些基础知识

所以我说...程序是虾饺? 程序是可以直接在电脑上执行,以完成某个目的或任务的一连串指令 换句话说,...