文章目录
-
- 1.分析登录过程
- 2.代码实现
1.分析登录过程
我们以github为例,分析登录的过程
打开 GitHub 的登录页面,链接为 https://github.com/login ,输入 GitHub 的用户名和密码,打开开发者工具,将 Preserve Log 选项勾选上,这表示显示持续日志,如下图所示。
点击登录按钮,这时便会看到开发者工具下方显示了各个请求过程,如下图所示。
点击第一个请求,进入其详情页面,如下图所示。
可以看到请求的 URL 为 https://github.com/session ,请求方式为 POST。再往下看,我们观察到它的 Form Data 和 Headers 这两部分内容:
Headers 里面包含了 Cookies、Host、Origin、Referer、User-Agent 等信息。Form Data 包含了 5 个字段,commit 是固定的字符串 Sign in,utf8 是一个勾选字符,authenticity_token 较长,其初步判断是一个 Base64 加密的字符串,login 是登录的用户名,password 是登录的密码。
综上所述,我们现在无法直接构造的内容有 Cookies 和 authenticity_token。下面我们再来探寻一下这两部分内容如何获取。
在登录之前我们会访问到一个登录页面,此页面是通过 GET 形式访问的。输入用户名密码,点击登录按钮,浏览器发送这两部分信息,也就是说 Cookies 和 authenticity_token 一定是在访问登录页的时候设置的。
这时再退出登录,回到登录页,重新访问登录页,截获发生的请求:
访问登录页面的请求如图所示,Response Headers 有一个 Set-Cookie 字段。这就是设置 Cookies 的过程。
另外,我们发现 Response Headers 没有和 authenticity_token 相关的信息,所以可能 authenticity_token 还隐藏在其他的地方或者是计算出来的。我们再从网页的源码探寻,搜索相关字段,发现源代码里面隐藏着此信息,它是一个隐藏式表单元素,如下图所示:
现在我们已经获取到所有信息,接下来实现模拟登录。
2.代码实现
首先我们定义一个 Login 类,初始化一些变量:
class Login(object):
def __init__(self):
self.headers = {
'Referer': 'https://github.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
'Host': 'github.com'
}
self.login_url = 'https://github.com/login'
self.post_url = 'https://github.com/session'
self.logined_url = 'https://github.com/settings/profile'
self.feed_url = 'https://github.com/dashboard-feed'
self.session = requests.Session()
这里最重要的一个变量就是 requests
库的 Session
,它可以帮助我们维持一个会话,而且可以自动处理 Cookies
,我们不用再去担心 Cookies
的问题。
接下来,访问登录页面要完成两件事:一是通过此页面获取初始的 Cookies
,二是提取出 authenticity_token
。
在这里我们实现一个 token()
方法,如下所示:
def token(self):
response = self.session.get(self.login_url, headers=self.headers)
selector = pq(response.text)
token = selector('input[name="authenticity_token"]').attr('value')
我们用 Sessio
n 对象的 get()
方法访问 GitHub 的登录页面,然后用 XPath 解析出登录所需的
authenticity_token` 信息并返回。
现在已经获取初始的 Cookies
和 authenticity_token
,开始模拟登录,实现一个 login()
方法,如下所示:
def login(self, email, password):
post_data = {
'commit': 'Sign in',
'utf8': '',
'authenticity_token': self.token(),
'login': email,
'password': password
}
response = self.session.post(self.post_url, data=post_data, headers=self.headers)
response = self.session.get(self.feed_url, headers=self.headers)
if response.status_code == 200:
self.dynamics(response.text)
response = self.session.get(self.logined_url, headers=self.headers)
if response.status_code == 200:
self.profile(response.text)
首先构造一个表单,复制各个字段,其中 email 和 password 是以变量的形式传递。然后再用 Session
对象的 post()
方法模拟登录即可。现在的github 关注人动态是通过ajax加载的,要向’https://github.com/dashboard-feed’ 发送请求。由于 requests
自动处理了重定向信息,我们登录成功后就可以直接跳转到首页,首页会显示所关注人的动态信息,得到响应之后我们用 dynamics()
方法来对其进行处理。接下来再用 Session
对象请求个人详情页,然后用 profile()
方法来处理个人详情页信息。
其中,dynamics()
方法和 profile()
方法的实现如下所示:
def dynamics(self, html):
selector = pq(html)
#print(selector.text())
dynamics = selector('div[class="d-flex flex-items-baseline"] div')
dynamics.find('span').remove()
#print(dynamics.text())
for item in dynamics.items():
dynamic = item.text().strip()
print(dynamic)
def profile(self, html):
selector = pq(html)
#print(selector.text())
name = selector('input[id="user_profile_name"]').attr('value')
email = selector('select[id="user_profile_email"] option[selected="selected"]').text()
print(name,email)
我们新建一个 Login 对象,记住下面要输入自己的邮箱和密码,然后运行程序,如下所示:
if __name__ == "__main__":
login = Login()
login.login(email='email', password='password')
完整代码如下:
import requests
from pyquery import PyQuery as pq
class Login(object):
def __init__(self):
self.headers = {
'Referer': 'https://github.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
'Host': 'github.com'
}
self.login_url = 'https://github.com/login'
self.post_url='https://github.com/session'
self.feed_url = 'https://github.com/dashboard-feed'
self.logined_url = 'https://github.com/settings/profile'
## 维持会话,自动处理cookies
self.session = requests.Session()
## 解析出登录所需要的
def token(self):
response = self.session.get(self.login_url, headers=self.headers)
selector = pq(response.text)
token = selector('input[name="authenticity_token"]').attr('value')
return token
def login(self, email, password):
#print(self.token())
post_data = {
'commit': 'Sign in',
'utf8': '',
'authenticity_token': self.token(),
'login': email,
'password': password
}
response = self.session.post(self.post_url, data=post_data, headers=self.headers)
response = self.session.get(self.feed_url, headers=self.headers)
if response.status_code == 200:
self.dynamics(response.text)
#print(response.text)
print("================================")
response = self.session.get(self.logined_url, headers=self.headers)
if response.status_code == 200:
self.profile(response.text)
## 关注人的动态信息
def dynamics(self, html):
selector = pq(html)
#print(selector.text())
dynamics = selector('div[class="d-flex flex-items-baseline"] div')
dynamics.find('span').remove()
#print(dynamics.text())
for item in dynamics.items():
dynamic = item.text().strip()
print(dynamic)
## 详情页面
def profile(self, html):
selector = pq(html)
#print(selector.text())
name = selector('input[id="user_profile_name"]').attr('value')
email = selector('select[id="user_profile_email"] option[selected="selected"]').text()
print(name,email)
if __name__ == "__main__":
login = Login()
login.login(email='2685764101@qq.com', password='password')
运行结果如下: