目录

爬虫相关的零碎知识

爬虫相关的零碎知识

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


提示:这里可以添加本文要记录的大概内容:

url、字符串、hex、base64、sign、MD5、hash系列算法介绍。


提示:以下是本篇文章正文内容,下面案例可供参考

    统一资源定位符,用来定位互联网上的某一个资料的
    http://域名/a/c/d.jpg?xxx=xxx&xxx=xxx

    协议://域名/a/b/c/d.jpg?username=xxx&pwd=xxx#
    请求:
        请求行
        请求头
        请求体
        
    响应:
        状态行
        响应头
        响应体

    域名:
        ip地址:端口号
        一台机器上可能会有多个使用网络的软件正在运行,
        在一个网卡上面会有65536tcp端口 65536udp端口 每一个网络应用程序都会监听一个端口

    /a/b/c
        虚拟路径,表示该应用程序对外提供的资源的路径(虚拟),可以理解成文件夹

    d.jpg
        具体的某一个资源。 jpgpng.

    ?后面
        表示的是参数。代表的是该资源是否有权限可以正常访问,
        服务器可以接收这些参数,进而进行相关的判断

    #
        锚点,作用在客户端的.表示当前页面被打开的时候。默认展示的内容是哪里

    注意,如果参数有一些特殊符号的话。整体的url的逻辑可能会产生非常大的偏差

    http://xxxx/user/login?user=&passwd=
    http://xxxx/user/login?user=&hello=123&passwd=123456
    本来应该有2个参数,但是由于特殊的字符出现.导致url的参数变成了3个,这里是有被注入的风险的。
    这就要求我们在传递参数的时候,要格外的注意,如果参数中有特殊的符号(包括中文)
    这种特殊的符号就必须要进行处理,处理成无害的等价的符号(urlencode)

    处理之后的内容,%XX
    处理逻辑:把你的特殊符号->处理成十六进制的ascii->前面加上%

    unicode -> 1-> 4
    gbk -> 1 -> 2
    utf-8 -> 1 -> 3
    %xx表示一个字节

urljoin、quote、urlencode、unquote、quote_plus基本使用如下

from urllib.parse import urljoin,quote,urlencode,unquote,quote_plus

s = "主业"
print(s.encode("utf-8")) # b'\xe4\xb8\xbb\xe4\xb8\x9a'
# b'\xe4\xb8\xbb\xe4\xb8\x9a'
print(str(s.encode('utf-8')).strip('b\'')) # \xe4\xb8\xbb\xe4\xb8\x9a
print(str(s.encode('utf-8')).strip('b\'').replace("\\x","%").upper()) # %E4%B8%BB%E4%B8%9A

# 当前页面的url
url1 = "http://www.baidu.com/a/b"
# xpath提取的
url2 = "/haha/hehe" # -> "http://www.baidu.com/haha/hehe"
url3 = "haha/hehe" # -> "http://www.baidu.com/a/haha/hehe"
#
# url1 + url2
print(urljoin(url1,url2)) # http://www.baidu.com/haha/hehe
# url1 + url3
print(urljoin(url1,url3)) # http://www.baidu.com/a/haha/hehe

my_params = {
    "username": "九黎",
    "password": "123456"
}
print(urlencode(my_params)) # username=%E4%B9%9D%E9%BB%8E&password=123456
# urlencode可以把字典类型的参数,直接处理成字符串(处理urlencode以及参数的拼接一次搞定)

# 很少用这个东西。因为requests模块自动就能帮你完成这个动作

import requests
url = "http://www.baidu.com"
my_params = {
    "username": "九黎",
    "password": "123456"
}
resp = requests.get(url, params=my_params)
print(resp.request.url) # http://www.baidu.com/?username=%E4%B9%9D%E9%BB%8E&password=123456
# 如果该网站的参数经过加密的。并且,。有的网站会在urlencode之后。进行加密。
# 加密(被urlencode之后的参数)
# 发请求(密文)

# 有一些特殊的网站,cookie的值,需要urlencode
# 这种cookie的一部分值需要urlencode的时候,此时,我们希望能不能只处理一小部分字符串

s = "http://www.baidu.com"
print(quote(s))
# http%3A//www.baidu.com
print(quote_plus(s))
# http%3A%2F%2Fwww.baidu.com

resp_text = "http%3A%2F%2Fwww.baidu.com"
# urldecode 解码
print(unquote(resp_text))
# http://www.baidu.com
#上述这个逻辑,只有在程序中真的要用的时候.
#如果你只是想知道这个值到底原文是什么,只是想看一眼...此时去找工具。不要写代码
# https://ctool.dev/tool.html

print("主业".encode("utf-8"))# b'\xe4\xb8\xbb\xe4\xb8\x9a'
计算机的底层:0 1
    你再电脑上看到的任何东西(电影,歌曲,文字,美女图片)
    101010100001000110->数字 -> 人类赋予了这些数字的显示效果。 -> 显示出来不同的文字和符号

    编码
    数字 -> 现实效果

    在不同的编码下。显示的文字是不同的
    10086 -> utf8
    10086 -> gbk

    我们看到的文字和符号,本质上就是数字

    a -> 0110 0001 97 -> 一个字节
    按照ascii的编排,一个文字符号,就是一个字节

    abc -> 0110 0001 0110 0010 0110 0011
        -> 97       98        99
        -> [97,98,99]

        一个字节,最大的字节: 1111 1111 -> 255
        可以用0~255 之间的数字, 表示一个字节

    中文状态(utf-8的逻辑)
    一个中文, 3个字节
    "主业" => \xe4\xb8\xbb\xe4\xb8\x9a
          => 60~255之间的数字
          => [228,184,187,228,184,154]
          js中没有字节 js中使用0~255之间的数字,来表示字节
    字节 -> 数字
    数字 -> 字节
    所有的加密解密逻辑都是从这里开始的
hex表示16进制的数字
    "主业" => [228,184,187,228,184,154]
          => 处理成十六进制
          => [e4,b8,bb,e4,b8,9a]
          => 把上面这东西拼接起来
          => e4b8bbe4b89a
          => 0-f组成的 一定是双数,2个代表一个字节
          => FF
          => 00~FF 0~255 => 一个字节
          => 任何字符串都可以处理成hex的形式
import binascii

s = "主业"
bs = s.encode("utf-8")
# bytes to ascii 保存成hex的形式
result = binascii.b2a_hex(bs)
print(result)
# b'e4b8bbe4b89a'
# 字节 => hex的形式
# hex => 字节
s = b'e4b8bbe4b89a'
# ascii to bytes ascii是hex形式
bs = binascii.a2b_hex(s)
print(bs.decode("utf-8"))
# 主业
s = "主业"
bs = s.encode("utf-8")

print(str(bs).strip("b'").replace("\\x",""))
# e4b8bbe4b89a
abc -> 01100001 01100010 01100011 # 按照8位一个字节的逻辑 3*8 = 24
        -> 011000 010110 001001 100011 # 4*6 = 24
        -> 24,22,9,33    最大0~64
        [0-9a-zA-Z+/]
        [10+26+26+2] => [64个东西]
        ls = ['0','1','2','3','4',5,6...a,b,c,d...A,B,C,D...+./]
        result = ls[24] + ls[22] + ls[9] + ls[33]
        result = "om9x"
    上述转化逻辑,被称为base64
    在该算法中,每三个字节为一组,拆分成4个文字符号.
    base64实际上是扩大了本来要传输的内容
    这种转化逻辑有一个优势,字节范围内的东西,大多是不可见的
    base64让所有的字节,都变成可见的字符串 方便传输和显示
    综上,我们看到的base64本质上是字节
    base64字符串和字节之间可以无缝转换
    转换过程中,如果字节的数量不够的情况,会在末尾补充= 保证数据可以正常还原回字节
ls = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
result = ls[24] + ls[22] + ls[9] + ls[33]
print(result)
import base64
s = "业主"
# 按照base64的逻辑,把字节处理成b64的组成
bs = base64.b64encode(s.encode("utf-8")).decode()
print(bs) # b'5Lia5Li7'
# 5Lia5Li7

s = "YWJj"
# 把b64的东西 按照b64的逻辑解码
bs = base64.b64decode(s).decode()
print(bs) # abc

# 使用场景,几乎都是把字节要进行传输的时候。处理成b64的字符串,传输
# 接收到之后,还原回字节,
    保证数据的一致性

    在发送请求之前,url,请求方式,参数,请求头,随机字符串,混合在一起,进行一个计算
    计算出来一个结果,该过程被称为签名,
    把该结果随着请求一同发送给服务器(包括随机值,时间)

    此时,服务器接收到的是url,请求方式,参数,请求头,随机字符串,时间...
    服务器会使用上述内容,再次进行同样的操作. 会计算出来宁一个结果.
    让计算出来的结果和客户端传递过来的签名值进行对比。如果一致。数据就没有被更改过。如果不一致,数据就是被调整过的.该过程被称为验签

    签名:拿着请求中的各种数据,进行混合,计算
    验签:拿着请求中的各种数据,进行混合,计算
    想要达到这样的效果,算法的选择就很重要,
    相同的数据计算出来的结果必须是一样的才可以.
    不同的数据计算出来的结果,极可能的不一样才行

    一般的签名算法会采用hash算法来完成.
    在众多的hash类的算法中md5是非常好用的(计算快,计算的结果比较小,重复率低)

    md5是摘要算法的一种。所以呢,会损失掉数据原有的特征.. 不可还原
from hashlib import md5
s = "123456"
obj = md5(s.encode("utf-8"))
print(obj.hexdigest())
# e10adc3949ba59abbe56e057f20f883e

# 123456 = 标准MD5算法 = > e10adc3949ba59abbe56e057f20f883e
# 计算过程是不可逆
salt = "sadasdasdas"
s += salt
obj = md5(s.encode("utf-8"))
print(obj.hexdigest())
from hashlib import sha1,sha256,sha512
s = "123456"
obj = sha1(s.encode("utf-8"))
print(obj.hexdigest())
# 7c4a8d09ca3762af61e59520943dc26494f8941b

s = "123456"
obj = sha256(s.encode("utf-8"))
print(obj.hexdigest())
# 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92