Python爬虫总结
最近临时写了个 python 爬虫的例子(核心代码不开源),总结下这次编写过程中的一些相关知识点与注意事项,以一个用 nodejs 写爬虫的开发者的角度去看待与比对。
编码
在抓包与协议复现的时候,出现中文以及特殊符号免不了 url 编码,python 的编码可以使用内置库 urllib,同时也能指定编码格式。
gbk 编码中文是占 2 个字节,utf8 编码中文占 3 个字节
url 编码
from urllib.parse import urlencode, parse_qs, quote, unquote
quote("夜里", encoding="gbk")
# %C0%A2%E2%F4
quot 还有一个 safe 参数,可以指定那个字符不进行 url 编码
quote("?", safe=";/?:@&=+$,", encoding="utf8")
# ? 加了safe
# %3F 不加safe
解码操作与编码同理
unquote("%C0%A2%E2%F4", encoding="gbk")
# 夜里
如果 编码格式错误,比如 gbk 编码用 utf8 解码将会变成不可见字符 ����,而用 utf8 编码用 gbk 解码,存在一个字节差,会输出成其他字符串,比如 你好
就会变成 浣犲ソ
,代码 unquote(quote("你好",encoding='utf8'), encoding="gbk")
URL 查询字符串
如果想构造一个 a=1&b=2
的 url 查询字符串,使用文本拼接很不现实。urllib 提供 urlencode 与 parse_qs 可以在查询字符串与字典中切换
urlencode({
"username": '夜里',
"password": 'a123456'
})
# username=%E6%84%A7%E6%80%8D&password=a123456
也有 encoding 与 safe 参数,配置同 quote,就不演示了。
parse_qs('a=1&a=2&b=2')
# {'a': ['1', '2'], 'b': ['3']}
将查询字符串转为 python 字典的话,值都是列表(应该是考虑可能会多个相同参数才这么设计)
小提一下,nodejs 中有个 querystring,方法 parse 与 stringify 与效果同理。
解构赋值
a,b = [1,2]
print(a,b)
user = {
"username": "night",
"password": "a123456"
}
username, password = user.values()
print(username, password)
print(user.keys())
# dict_keys(['username', 'password'])
print(user.values())
# dict_values(['night', 'a123456'])
解构赋值没什么好说的,和 js 类似,只不过对字典的解构赋值的话,要取值则要调用 values(),取 key 的话默认不填,但是也可以调用 keys()
模板字符串
user = 'night'
print(f'username: {user} age: {20+1}')
# username: night age: 21
同样中可以编写表达式,与 js 的模板字符串类似
如果是 python3.6 之前的话,则是用使用 string.format 方法(不常用,也不好用)
"username: {} age: {}".format("夜里", 18)
而 js 中的模板字符串则是使用反引号`和$,像下面这样
user = 'night'
console.log(`username: ${user} age: ${20+1}`)
# username: night age: 21
字典
python 的字典与 js 的对象有些许相像,个人总体感觉没有 js 的对象灵活,演示如下
user = { 'username':'night','password':'a123456' }
print(user['username'])
想要获取字典中的值,就需要写成user['username']
,如果习惯了 js 的写法(比如我),就会习惯的写成user.username
,这在 python 中将会报错,AttributeError: 'dict' object has no attribute 'username'
,并且字典的 key 还需要使用引号进行包裹,如果是 js 的话,代码如下
user = { username: 'night', password:'a123456'
console.log(user.username)
如果想在 key 中包裹引号也是可以的,省略引号相当于代码简洁,同时取值也可以像 python 中的user['username']
来进行取值,相对灵活。
假设我想取 user 的 age 属性,但是 user 没有 age 属性,python 则是直接报错KeyError: 'age'
,可以使用user.get('age',20)
,如果没有 age 属性,则默认 20。而 js 是不会报错,则是会返回undefiend
,如果想要默认值的话可以像这样,user.age || 20
。毕竟 js 调用类的方法属性都是可以直接 对象.属性
对象.方法
,而 python 中是 对象["属性"]
对象.方法
,只能说各有各的优劣吧 。
不过 js 不确定是否有该属性的话,可以使用?.
,比方user?.age
,这样返回的null
,而不是undefiend
。
字典['属性值']
获取,key 需用引号包裹