一些日常用的上的计算机技术(一)
本文最后更新于 2024年11月26日 上午
一些日常用的上的计算机技术(一)
写在前面
在 AI 背景下,很多日常处理数据的工作完全可以交给 AI 来完成,学习它们的必要性似乎已经不那么强?
在大模型时代,更重要的是了解一些技术的存在,而非具体掌握这些技术,本文旨在提出某些可能对日常工作有帮助的技术,大致给出一个框架。
最后,我想说,一个全栈工程师,需要掌握的不是整个计算机系统中所有方向的技术,而是整个计算机系统的脉络。当一个需求被提出时,他能够沿着大脑中的脉络找到所需的枝叶技术,并运用自己熟练的信息检索能力来找到它们的技术细节,并最终将这些技术组合成解决方案。
可持久化
其实用 “可持久化” 来形容它并不准确,这也包括把 hardcode 部分分离以便让用户不必修改源代码运行程序的相关技术。
举例来说比如爬虫要爬一个网站,你有可能直接把一些参数写进代码里,例如:
1
2
3
4
5URL = "www.google.com"
PROXY = {
http_proxy: "localhost:7890",
https_proxy: "localhost:7890"
}但是你某一台电脑的代理端口是
localhost:7891
,所以一个方案是直接修改源代码,但是这太麻烦了,因为代码可能会比较长然后你需要翻。所以一个方案是单独把一些可能会变的配置给提出来单独写一个配置文件,然后每次运行代码的时候你输入配置文件的路径,或者仅 hardcode 配置文件路径。这样都比一个个改参数更好。
配置文件可以用 .yaml 或者 .json 文件,我习惯用前者,但其实后者的适用性更广,大部分编程语言内置了处理 .json 文件的相关函数。
yaml 使用:
准备:
1
pip install PyYaml
读取:你大可直接复制下面的代码。
1
2
3
4
5
6def yaml2dict(file_path, encoding='utf-8'):
if check_suffix(file_path, 'yaml'):
with open(file_path, 'r', encoding=encoding) as f:
return yaml.safe_load(f)
else:
raise ValueError("file suffix name not support")写入:用
yaml.safe_dump(obj, stream)
- obj:一个 Python 对象,一般只支持基本数据类型。
- stream:一个可写流对象,可以用
with
操作打开。
批量发送电子邮件
用
email
和smtplib
来发送,这俩是标准库,不用安装。大概可以看看下面的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
def send_mail(receiver, html, subject):
message = MIMEMultipart("alternative") # 交替 attach 模式
message["Subject"] = subject # 邮件标题
message["From"] = SENDER # 发送者邮箱
message["To"] = receiver # 接收者邮箱
part = MIMEText(html, "html", "utf-8") # 三个参数是: html 字符串, 格式名, 编码方式
message.attach(part) # 将对应的 part 正式加入 message
# SMTP服务器和端口,这是 google 邮箱的网址和端口,服务器和端口取决于发送者的邮箱。
smtp_server = "smtp.gmail.com"
port = 587
try:
server = smtplib.SMTP(smtp_server, port) # 建立 SMTP 连接
server.starttls() # 启用TLS安全传输模式
server.login(SENDER, PWD) # 两个参数分别为邮箱账号和密码
server.sendmail(SENDER, receiver, message.as_string()) # 发送
print("邮件发送成功")
except Exception as e:
print("邮件发送失败", e)
finally:
server.quit() # 断开服务器连接
Excel/Word 处理
Excel 处理
我使用的是 pandas 库。
1
2pip install pandas
pip install openyxl这样读取:
1
2
3
4import pandas as pd
xls = pd.ExcelFile(r"C:\Users\huany\Desktop\帆软杯\第六届帆软杯报名信息(" + group + f") - 含准入码.xlsx")
sheet_name = xls.sheet_names[0]
df = pd.read_excel(xls, sheet_name=sheet_name)df 是转出来的 DataFrame 对象,有以下几个注意点:
- 一个表格的第一行自动作为表头,每一列的内容作为索引指标。
- 用
df['col_name']
来获取一列,它是一个iterable
对象。 - 用
df.iterows()
来迭代每一行,得到的行是一个类dict
对象,用表头的数据作为指标。
Word 处理
- word (.docx 文件)是基于 xml 的文档。
- .docx 文件本质是一个 zip 文件,改一下后缀名就可以解压。
- 主要文字是放在
/word/document.xml
,似乎每个文本可以检索到两次,把这两个都改了,然后压缩回去就可以实现改动 .docx 文件。 - 可以看看我新开的开源项目。
selenium 爬虫
cloudflare 等工具的广泛使用使得传统的 requests 爬虫适用性逐步降低,如果没有太高的性能要求,不妨使用 selenium 这样的更上层的库来实现爬虫功能。
关于消除自动化特征
使用
undetected_chromedriver
库可以消除大部分的自动化特征。1
pip install undetected-chromedriver
使用方式和传统 selenium 几乎相同,有两点注意。
1
2options = uc.ChromeOptions()
driver = uc.Chrome(use_subprocess=True, options=options)uc.ChromeOptions()
是该库准备的消除自动化特征的 options 参数use_subprocess
的功能是让WebDriver
在独立的进程中运行,不受主进程崩溃的影响。(其实可以不管)
关于配置自动下载
用
perfs
可以配置自动下载相关的功能1
options.add_experimental_option("prefs", CONFIG.PREFS)
参数值是一个 dict,常用的参数有:
1
download.prompt_for_download: false # 不要弹出提示框选择下载路径
似乎配置默认下载路径的办法无法生效。
lazy load
有时候不太想等待所有资源加载完毕,可以使用
page_load_strategy
来控制1
options.page_load_strategy = 'eager'
- “eager” 不会加载图片等资源,初步解析完成后便会返回。
page_load_strategy
是ChromeOptions
类定义的一个属性。
处理网页
用 BeautifulSoup 库可以来层次化读取和处理整个 html 页面。
1
2
3import BeautifulSoup
soup = BeautifulSoup(driver.page_source, "html.parser")
all_artist = soup.find("div", class_='home-rows-videos-wrapper')BeautifulSoup.find()
可以通过标签名和class
属性来查找,返回值同样是一个结构化的 HTML 对象,仍然有find
等方法。
一些关于 HTTP 请求的小知识
看 http 请求的时候,有时候 payload 是没有数据的,数据可以通过 headers 传递。
请求一个超大二进制文件时可能的 headers:
1
2
3headers = {
'Range': f'bytes={0}-'
}
压缩文件的处理
Python 一般选用 zipfile 来出来压缩文件。
zipfile 的打开方式和文件流对象差不多,都需要用 with
指定打开模式,文件名,编码等信息。
解压
1 |
|
- 若不存在,
extracted
目录会被自动创建。 folder/subfolder/file.txt
是以 .zip 文件中,被压缩文件的目录,解压后,extracted
目录会视为其根目录,然后解压过程保持目录结构不变,中间不存在的目录自动创建,也就是说解压出来folder/subfolder/file.txt
会位于extracted/folder/subfolder/file.txt
。extractall
即对每一个压缩文件中的文件做extract
操作。
压缩
1 |
|
注意到 ZipFile.write() 有两个参数,这个函数用于把一个文件添加到压缩文件对象中,第一个参数是被添加的文件的路径,第二个参数是压缩文件中,被压缩文件的路径。
第二个参数如果留空则默认为第一个参数。
例如,这个
new_example.zip
压缩文件的目录结构如下:1
2
3
4
5new_example.zip:
├── file1.txt
└── folder1/
└── folder2/
└── file3.txt它不支持直接压缩一个文件夹,所以如果要压缩文件夹需要用
os.path.walk()
方法来遍历文件并添加。1
2
3
4
5
6
7
8
9
10
11with zipfile.ZipFile(zip_file_path, 'w') as zipf:
for root, dirs, files in os.walk(folder_path):
for file in files:
# 创建文件的绝对路径
file_path = os.path.join(root, file)
# 创建文件在ZIP中的相对路径
# 这里使用 os.path.relpath() 来获取相对于 folder_path 的相对路径
# 这样ZIP文件中的目录结构会与原始文件夹结构相同
arcname = os.path.relpath(file_path, start=folder_path)
zipf.write(file_path, arcname)root
是正在遍历的目录路径,dirs
是该目录下所有子目录的名字列表(相对root
的路径),filenames
是该目录下所有文件的文件名(相对root
的路径)。