基本的认证
‘User-Agent’: ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64)…等’ 而 python 模拟请求默认发送的是 python-requests/2.32.4 具体可以在控制台查看
“refer”: 告诉服务器你进入此URL的来源是哪里
CSV写入
with open(output_file, mode="w", encoding="utf-8", newline="") as f: ...
with … as f 是上下文管理器,它会在代码块结束时自动调用 f.close(),不需要再手动调用
| 模式 | 文件存在时 | 文件不存在时 | 典型用途 |
|---|---|---|---|
"wb" | 清空内容 | 创建文件 | 普通的二进制("w"是文本)写入操作,不关心文件之前是否存在 |
"x" | 报错 | 创建文件 | 确保创建全新文件,防止意外覆盖重要文件 |
"a" | 追加内容 | 创建文件 | 日志文件,持续记录 |
注意,在文本模式下("w"),写入数据时会发生隐式的编码转换(如Windows,换行符\n会被转换为\r\n)。对于图片、视频、压缩包等二进制(非文本)文件,这种转换会损坏文件。
而"wb" 模式会禁止任何转换,将数据原封不动、按字节写入文件。
newline=”” 保证 CRLF 和 LF 格式都能被正常识别位换行符
按顺序排列写入 CSV
定义顺序 -> 告诉 CSV 顺序 -> 按顺序写入 CSV
fieldnames = ["name", "year", "rating", "comment"] # 定义
writer = csv.DictWriter(f, fieldnames=fieldnames) # 告诉 CSV 有哪些列
writer.writeheader() # 写入顶部
...d = m.groupdict()
# 按照 fieldnames 的顺序写,没有就是空白
writer.writerow({k: d.get(k, "") for k in fieldnames})
HTML 实体转换
类似 · 中点符号, 不换行空格, < <
这些在请求后会直接拿到原文,需要导入 html 包(import html)转化才能显示平时看到的样子
s = “电影喵·最新电影”
print(html.unescape(s))
正则,bs4,与Xpath 都可以指定要爬取的位置或元素,但是我们推荐 Xpath 相对路径(依赖如id,class这样的),如 /div[@class="search-result"]/text()
res = requests.get(URL, headers=HEADERS, timeout=15)
content = etree.HTML(res.text)
divs = content.xpath("????")
代理
原理是通过第三方机器去请求
res = requests.get(URL, proxies=PROXIES, timeout=10) # 加上 proxies 即可
进程与线程
基本概念
进程(Process)是一个正在运行的程序,是操作系统资源分配和调度的基本单位(一般不怎么用,消耗太大)
线程(Thread)是进程中的一个执行单元,是 CPU 调度的最小单位
针对不同线程 / 进程 (这两个代码高度相似)传参,格式是元组,如
def func (test):
print(test)
f1 = Thread(target=func, args=("喵喵",)) # 没逗号就是字符串了
线程池(ThreadPoolExecutor) / 进程池(ThreadPoolExecutor)
用户一般会再开辟多个线程后,把任务交给线程池,让其分配资源执行任务,用户不需要关心分配调度
with ThreadPoolExecutor(50) as t:
t.submit(function)
aiohttp 与异步操作
async def aiodownload(url):
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=HEADERS) as res: # 这里与requests语法基本一致
with open(f"{url.split('/')[-1]}.jpg", "wb") as f:
f.write(await res.content.read()) # 比requests多一个read()
async def main():
tasks = []
for url in URLS:
tasks.append(aiodownload(url))
await asyncio.gather(*tasks) # 并发的执行与返回结果
解密
一般的流程大体上是:
读取源文件 – 解密 – 写入解密好的文件
# 创建 AES-CBC 模式的解密器对象
aes = AES.new(key=key, IV="{key的长度所对应的0的个数}, mode=AES.MODE_CBC"
async with aiofiles.open(... rb) as f1,\
aiofiles.opem(... wb) as f2:
bs = await f1.read()
# 读取的加密文件内容 bs 用 AES 解密后写入新文件
await f2.write(aes.decrypt(bs))
解密好的文件写入
async with aiofiles.open(... r) as f:
... get the filename
task = asyncio.create_task(dec_ts(filename, key))
tasks.append(task)
await asyncio.wait(tasks)