前言
前面写的代码虽然完成了爬取的功能,但是过于凌乱,于是打算重构一遍。首先从登陆开始。
前文传送门:
个人博客本文传送门:
改进前的代码
面向过程
这是第一次写的登录函数,获取登录信息和登录本身是放在一起的。
def login():
"""
登录并返回已经登录的会话
:return: 已经登录的会话(session)
"""
#设置
login_url = 'http://ids.chd.edu.cn/authserver/login?service=http%3A%2F%2Fportal.chd.edu.cn%2F'
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
}
#新建会话
session=requests.session()
#获取登录校验码
html=session.post(login_url,headers=headers).text
soup=BeautifulSoup(html,'lxml')
lt=soup.find('input',{'name':'lt'})['value']
dllt=soup.find('input',{'name':'dllt'})['value']
execution = soup.find('input', {'name': 'execution'})['value']
_eventId = soup.find('input', {'name': '_eventId'})['value']
rmShown = soup.find('input', {'name': 'rmShown'})['value']
login_data={
'username': input("请输入学号:"),
'password': input("请输入密码:"),
'btn':'',
'lt': lt,
'dllt': dllt,
'execution': execution,
'_eventId': _eventId,
'rmShown': rmShown
}
#登录
response=session.post(login_url,headers=headers,data=login_data)
if response.url=='http://portal.chd.edu.cn/':
print('登录成功!')
return session
面向对象
第二次是将全部函数封装到类中,这次将获取登录信息从其中分出来。但是两者关系仍然太过于紧密。
class spider:
'''
爬虫类
'''
def __init__(self,headers):
self.session=requests.session()#初始化登录session
self.is_login=False#登录状态
self.headers=headers#头信息
self.cookiejar=http.cookiejar.LWPCookieJar('cookie.txt')
def get_login_data(self,login_url):
'''
获取登录需要的数据
:param login_url: 登录页面url
:return: 一个存有登录数据的字典
'''
# 获取登录校验码
html = self.session.post(login_url, headers=self.headers).text
soup = BeautifulSoup(html, 'lxml')
lt = soup.find('input', {'name': 'lt'})['value']
dllt = soup.find('input', {'name': 'dllt'})['value']
execution = soup.find('input', {'name': 'execution'})['value']
_eventId = soup.find('input', {'name': '_eventId'})['value']
rmShown = soup.find('input', {'name': 'rmShown'})['value']
login_data = {
'username': input("请输入学号:"),
'password': input("请输入密码:"),
'btn': '',
'lt': lt,
'dllt': dllt,
'execution': execution,
'_eventId': _eventId,
'rmShown': rmShown
}
return login_data
def login(self,login_url):
"""
登录并返回已经登录的会话
:return: 已经登录的会话(session)
"""
if self.load_cookie():
self.is_login = True
else:
#获取登录信息
login_data=self.get_login_data(login_url)
# 登录
response = self.session.post(login_url, headers=self.headers, data=login_data)
if response.url!=login_url:
print("登录成功")
self.is_login=True
self.save_cookie()
else:
print("登录失败")
return self.session
#省略后面的函数
改进
这次改进,我打算让login()
函数与获取登录信息用的函数关系没有那么紧密,让后者可以被替换或者不用。
所以使用了回调函数,也就是将函数指针作为参数传入,不过python变量本身就像指针一样,直接传变量即可。
函数头
def login(self,login_url,login_data_parser=None,target_url=None):
传入了三个参数,
- login_url : 显而易见,这是登录页面的url
- login_data_parser : 这是一个函数,用于解析页面中随机生成的隐藏域代码的函数,可以不传入
- target_url : 用于判断是否登录成功,这是登录之后会跳转到的页面
获取登录信息
接着判断参数是否为函数(是否可调用),如果可以调用,就调用它获取登录信息。在这里不需要关心函数内部具体如何获取,而只用关心它的接口。
这个函数的返回值是一个装有登录信息的dict,和一个cookies。
def login(self,login_url,login_data_parser=None,target_url=None):
login_data=None
#get the login data
if(login_data_parser!=None and callable(login_data_parser)):
login_data,cookies=login_data_parser(login_url)
登录
然后就完成了
def login(self,login_url,login_data_parser=None,target_url=None):
'''
login
:param login_url: the url you want to login
:param login_data_parser: a callback function to get the login_data you need when you login,return (login_data,response.cookies)
:param target_url: Used to determine if you have logged in successfully
:return: response of login
'''
login_data=None
#get the login data
if(login_data_parser!=None and callable(login_data_parser)):
login_data,cookies=login_data_parser(login_url)
#login
response=requests.post(login_url,headers=self.headers,data=login_data,cookies=cookies)
if(target_url!=None and response.url==target_url):
print("login successfully")
self.cookies=cookies
return response
获取登录信息函数
这个和前面就是一样的了。只要修改传给login函数的函数,就可以获取不同网站的登录信息。login函数变得更加通用了,不再过于依赖登录信息函数存在。
def chd_login_data_parser(self,url):
'''
This parser is for chd
:param url: the url you want to login
:return (a dict with login data,cookies)
'''
response=requests.get(login_url)
html=response.text
# parse the html
soup=BeautifulSoup(html,'lxml')
lt=soup.find('input',{'name':'lt'})['value']
dllt=soup.find('input',{'name':'dllt'})['value']
execution = soup.find('input', {'name': 'execution'})['value']
_eventId = soup.find('input', {'name': '_eventId'})['value']
rmShown = soup.find('input', {'name': 'rmShown'})['value']
login_data={
'username': input('input account:'),
'password': input('input passwd:'),
'btn':'',
'lt': lt,
'dllt': dllt,
'execution': execution,
'_eventId': _eventId,
'rmShown': rmShown
}
return login_data,response.cookies