2021-03-01

模拟登陆并爬取Github

前言:如果希望爬取GitHub上所关注的人的最近动态或者你的个人信息(如name,email)我们就需要模拟登陆去爬取信息

  • 分析登陆过程
    需要探究后台的登陆请求是怎样发送的,登陆之后又有怎么样的处理过程

先打开GitHub的登陆页面,链接是 https://github.com/login
输入用户名和密码,打开开发者工具,把Preserve Log选项勾选上,这表示显示持续日志
然后点击登陆按钮,这时就会看到开发者工具下各个请求过程。

在这里插入图片描述
点击session请求

在这里插入图片描述
可以看到请求的URL为 https://github.com/session ,请求方式为POST
然后观察Form Data 和Headers这两部分

Headers包含了Cookies、Host、Origin、Referer、User-Agent等信息。Form Data 包含了5个字段,commit是固定的字符串Sign in,anthenticity_token初步判断是一个Base64加密的字符串。login是登录的用户名,password是登录密码

综上所述,我们无法直接构造的内容有Cookies 和 authenticity_token

在登录之前我们会访问到一个登录页面,此页面是通过GET形式访问的。输入用户名密码,点击登陆按钮,浏览器会发送这两部分信息,也就是说Cookies和authenticity_token一定是在访问登录页的时候设置的。
这时候再退出登陆,回到登录页,同时清空Cookies,重新访问登录页,截获发生的请求

在这里插入图片描述

Response Headers有一个Set-Cookies字段。这就是设置Cookies的过程

另外我们发现,Response Headers没有相关authenticity_token的信息。所以很有可能authenticity_token还隐藏在其他的地方或者是被计算出来的。我们再从网页的源码去搜索相关的字段,发现源码里面隐藏着这个字段,它是一个隐藏式表单元素。

在这里插入图片描述
OK!我们已经获取到所有的信息了

#Xpath版本


import requests, re
from lxml import etree
#定义一个Login类初始变量,其中最重要的变量就是requests库里的Session,它可以帮助我们维持会话,而且自动处理Cookies
class Login(object):
    def __init__(self):
        self.headers = {
            'Referer': 'https://github.com/',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 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'
        self.session = requests.Session()

#用Seesion对象的get()方法去访问Github的登陆页面,然后用Xpath去解析出登陆所需的authenticity_token信息并返回
    def token(self):
        response = self.session.get(self.login_url, headers=self.headers)
        selector = etree.HTML(response.text)
        token = selector.xpath('//div//input[1]/@value')[0]
        return token

#已经获取初始的Cookies和authenticity_token,构造一个表单,复制各个字段,其中email和password以变量的形式传递,然后用Session对象的POST()方法模拟登录即可。
    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)
            # print('response.text', response.text)

        response = self.session.get(self.logined_url, headers=self.headers)
        if response.status_code == 200:
            # print(response.text)
            self.profile(response.text)
                    
#
    def dynamics(self, html):
        print('*'*10+'dynamicing'+'*'*10)
        selector = etree.HTML(html)
        # print("*"*20, etree.tostring(selector).decode('utf-8'))
        # print(selector.xpath('//div[@class="d-flex flex-items-baseline"]'))
        dynamics = selector.xpath('//div[@class="d-flex flex-items-baseline"]//div')
        # print(dynamics)
        for item in dynamics:
            etree.strip_elements(item, 'span')
            dynamic = ' '.join(item.xpath('.//text()')).replace('\n', ' ').strip()
            dynamic = re.sub(' +', '  ', dynamic)
            print(dynamic)
        print('*' * 10 + 'dynamic end' + '*' * 10)

    def profile(self, html):
        print('*'*10+'profileing'+'*'*10)
        selector = etree.HTML(html)
        name = selector.xpath('//input[@id="user_profile_name"]/@value')[0]
        email = selector.xpath('//select[@id="user_profile_email"]/option[@value!=""]/text()')[0]
        print(name, email)

if __name__ == '__main__':
	login = Login()
	login.login(email='email',password="password')
Pyquery版本


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)
		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='email',password='password')

登陆成功相当于建立了一个Session会话,Session对象维护着Cookies的信息,直接请求就会得到模拟登录成功后的页面。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Micek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值