目录
一、原理
以下内容为使用requests库发送请求,使用cookie/session模拟登录(并且登录时只需输入账号与密码)。
我们在使用搜索引擎访问网页时,会向访问的网页发送请求,被请求的网页的服务器对请求进行处理(无异常),会返回请求的数据。在搜索引擎发送的请求包中,存在请求头:Requests Headers(关键),携带的部分参数如下:
authority:访问的网址
method:参数传递的方式
path:访问的路径
scheme:传输使用的协议
accept:传输的内容格式/类型
accept-encoding:传输的编码方式
accept-language:传输语言
cache-conctrol:缓存控制
cookie:身份标识(有很多编码方式)
模拟登录的过程需要使用到,authority,method,cookie等参数携带的信息,authority提供了发起请求的url,method提供了发送请求的方法,cookie提供了身份标识,也就是说,我们知道目的地(authority),以及到达目的地的方法(method),以及身份标识(cookie)就能轻松的做到模拟登录。
其中比较重要的是cookie,那么它是因为什么而出现的呢?早期互联网用户不多,需要缓存的数据量较少,但经过时间的推移,互联网飞速发展,互联网用户与需要缓存的数据越来越多(业务多),服务器难以处理如此多的数据(每次登陆都需要重新处理用户登陆数据并返回给用户),这时候就需要一个东西来进行每个用户的身份标识,用来提高速度与节约空间,cookie由此而生(单从数据缓存与用户身份标识方面)。
以下是用户发起访问请求简要过程:
以下是被用户发起访问请求网页简要回复过程:
在之后我们访问该网页时,因为cookie的存在,在cookie未失效时(cookie具有时效性,一般由网页设定,不同网页设定时间不同),我们可以直接登录之前账户的身份。
那么ssesion的出现则是cookie在服务器端的体现,cookie在服务器所维持的会话成为了ssesion。
以上内容可以知道,大体步骤为:1、登录,2、找到我们登录时发送的数据包(一般是login)3、把相关的参数进行保存,进行模拟登录。
二、实际操作
2.1、确认目标
目标一(小说网页,爬取热门小说不付费章节,需要付费的章节是需要付费才能加载出页面内容(也就是说付费了才能爬,但是付费了直接看不就完事了还爬取干啥))、目标二(学校官网)、
2.2、目标一实操
2.2.1、打开搜索引擎开发者工具(F12或者Fn+F12),找到Network,注意要把Preserve log,Disable cache(禁止缓存)勾选上,否则有可能抓不到登录的login包。
2.2.2、进入登录界面
2.2.2.1、点击登录
2.2.2.2、这时候会出现很多抓到的包,我们寻找有login,lo,log,l等字眼的包,发现两个login包
2.2.2.3、输入账号和密码进行登录,再次查看包所携带的内容
发现我们传递的数据是我们输入的账号与密码,那么我们构建一个字典payload把参数构造完成,并输入正确的账号与密码即可模拟登录。
2.2.2.4、上代码
导库、
import requests
在抓到的包拿url:
url = "https://passport.17k.com/ck/user/login"
构造payload的数据->data
data = {
"loginName": "注册的用户名",
"password": "密码"
}
构建ssesion并发送请求,输出结果
session = requests.session()
resp = session.post(url, data=data)
resp.encoding = 'UTF-8'
print(resp.text)
结果如下
接下来要获取小说网页内容:
逻辑思路:
1、在第一层获取到第二层的url,在第二层获取第三层的url如此反复,直到可以看到爬取的内容为止。
1层->2层
2层->3层
3层->4层
4层->爬取的内容(章节)
2.3、需要检查源代码进行内容的爬取(鼠标右键空白处,查看页面源代码,找到需要爬取的部分进行分析);
编码如何选择?
进入页面源代码,找到charset,编码不正确爬取到的内容返回是乱码的,根本看不懂;
2.4、源代码
import requests
import re
'''
模拟登录并爬取17K小说免费内容进行测试(测试热门单本小说)
'''
def install():
max_url = "https://www.17k.com" # 总页面url
url = "https://passport.17k.com/ck/user/login" # 模拟登录页面url
# 热门小说url,这个url可以直接爬取
one_url = "https://www.17k.com/top/refactor/top100/01_subscribe/01_subscribe__top_100_pc.html"
# 构造利用的payload
data = {
"loginName": "注册的账号",
"password": "注册的密码"
}
# 维持会话
session = requests.session()
session.post(url, data=data) # 登录
resp = session.get(one_url) # 使用之前登录的信息进行会话维持
resp.encoding = 'UTF-8' # 对请求到的内容进行解码
# 第一层跳转
one_pape_content = resp.text # 第二层源代码
one_obj = re.compile(r'<div class="list">.*?<li>.*?f="(?P<href>.*?)"', re.S) # 正则提取链接
one_result = one_obj.finditer(one_pape_content)
for i in one_result:
two_url = i.group("href") # 提取出正则的链接
two_url = max_url + two_url # 拼接链接
# 第二次发起请求
# 第二层跳转
two_resp = session.get(two_url)
two_resp.encoding = 'UTF-8'
two_pape_content = two_resp.text
two_obj = re.compile(r'<td><a class="red" href=.*?a class="red" href="//(?P<one_url>.*?)".*?tle="(?P<one_name>.*?)"', re.S)
two_result = two_obj.finditer(two_pape_content)
print("开始爬取:")
for j in two_result:
tw_href = j.group("one_url") # 每一部小说链接
tw_name = j.group("one_name") # 上面链接对应的名字
# 第三层跳转,这里拿到的是热门小说全部的链接,和名字
three_resp = session.get('https://'+tw_href) # 使用之前登录的信息进行会话维持
three_resp.encoding = 'UTF-8'
three_pape_content = three_resp.text # 第三层源代码
# print(three_pape_content)
# print("以上内容是第三层网页源代码")
three_obj = re.compile(r'<dl class="Bar">.*?<a href="(?P<th_href>.*?)"', re.S) # 正则提取链接
three_result = three_obj.finditer(three_pape_content)
for k in three_result:
three_href = k.group("th_href")
three_hrefs = max_url + three_href
# 第四层跳转
four_resp = session.get(three_hrefs) # 使用之前登录的信息进行会话维持
four_resp.encoding = 'UTF-8'
four_pape_content = four_resp.text # 第四层源代码
four_obj = re.compile(r'<a target="_blank".*?href="(?P<fou_href>.*?)".*?title="(?P<item_name>.*?)">', re.S) # 正则提取链接
four_result = four_obj.finditer(four_pape_content)
for ll in four_result:
four_href = ll.group("fou_href")
if four_href == "//www.4yt.net/": # 去除无用链接
four_href = ""
else:
four_hrefs = max_url + four_href # 第四层url print(four_hrefs)
# 第五次请求,请求到小说内容,并下载
five_resp = session.get(four_hrefs) # 使用之前登录的信息进行会话维持
five_resp.encoding = 'UTF-8'
five_pape_content = five_resp.text # 第四层源代码
five_obj = re.compile(r'<div class="p">.*?<p>(?P<pape_text>.*?)</p>', re.S) # 正则提取
five_result = five_obj.finditer(five_pape_content)
# 遍历写入内容
for out in five_result:
all_pape = out.group("pape_text")
with open("pape.txt", mode="a", encoding='UTF-8') as f:
f.write(all_pape)
f.write('\n')
f.write(' ')
f.close()
# 只测试一本小说
if tw_href == "www.17k.com/book/3390123.html":
break
if __name__ == '__main__':
install()
print("爬取结束:")
说明:页面源代码分析比较重要,本次使用re进行解析,代码重复部分较多,并且构造正则表达式需要更多的思考。
三、结果
节省时间,只爬取了5秒左右。
四、问题与总结
4.1、问题
4.1.1、代码块优化,可读性与移植性
4.1.2、如何避免大量重复代码?
4.1.3、如何选择合适的解析方式?
4.1.4、爬取到的内容如何更好的保存与显示?
4.2、总结
4.2.1、模拟登录成功
4.2.2、爬取内容成功
4.2.3、多学习
本次内容虽然没有直接使用cookie进行登录,但是使用的ssesion是cookie的一种表现形式(服务器端),直接使用cookie的代码不进行展示(cookie具有时效性,使用具有限制)。
以上内容均为学习过程,无商业行为,若有错误或问题欢迎指出。