网络爬虫 —— 配置文件解析
ini
ini
( Initialization File
)顾名思义,主要用于初始化应用程序。这是一种无固定标准格式的配置文件,且文件没有固定的后缀,常见的有 .ini
、 .conf
、.cfg
,甚至还可以是 .txt
。主要用于 Windows
操作系统上,但也有很多程序会采用 INI
文件作为配置文件使用。
文件格式
ini
格式在不同的解析器中会具有不同的特征,比较固定的是:
- 节:使用中括号包裹的字符串,其后面的所有参数(到下一个小结的开始之前),都归属于该节
[section]
- 参数:以键值对的方式设置参数值,即程序中需要访问的参数所对应的值
name = value
- 注释:以
;
或#
开头的行表示的是注释信息
; comment text
# comment line
- 大小写不敏感
section
中的参数顺序与其在文件中出现的顺序无关
除了上面的基本特征之外,不同的解析器可能还提供了
- 全局属性
- 冒号(
:
)或空格分隔的键值对声明方式 - 层次或嵌套形式的
section
- 重复参数名称
- 参数引用等
示例
在 demo.ini
中输入下面的文本并保存
[DEFAULT]
; default directory
path = /usr/bin
# P value cut off
cut_off = 0.05
[PROGRAMS]
python = /path/to/python
R = /path/to/R
R 解析文件
在 R
中,我们使用 configr
包来读写常见的 4
种配置文件,该包是对 ini
、jsonlite
、yaml
和 RcppTOML
这 4
个包的封装,内核还是通过调用它们来对不同格式的文件进行解析的。
首先需要安装该包
# CRAN
install.packages('configr')
# Github
# install.packages("devtools")
devtools::install_github("Miachol/configr")
导入包
library(configr) # version 0.3.5
读取文件
使用 read.config
函数即可读取文件
conf <- read.config("demo.ini")
class(conf)
# [1] "list"
str(conf)
# List of 2
# $ DEFAULT :List of 2
# ..$ path : chr "/usr/bin"
# ..$ cut_off: chr "0.05"
# $ PROGRAMS:List of 2
# ..$ python: chr "/path/to/python"
# ..$ R : chr "/path/to/R"
该函数返回一个嵌套的 list
对象,第一层为节,第二层为参数值。可以在程序中以访问 list
的形式获取配置文件中的参数信息。
该解析器提供了一些额外的特征,通过预先在文件中设置一些占位符,并在占位符中添加相应的命令,然后在读取时进行解析。主要通过几个参数来控制
参数 | 功能 |
---|---|
extra.list |
用字符串 list 来替换 {
{}} 包裹的字符 |
other.config |
导入其他配置文件 |
rcmd.parse |
是否将 @>@ 包裹的字符串作为 R 命令执行 |
bash.parse |
是否将 #># 包裹的字符串作为 bash 命令执行 |
glue.parse |
是否执行 glue 命令 |
glue.flag |
设置 glue 命令的起始标志,默认为 !!glue |
demo.ini
文件里面写入如下内容
[DEFAULT]
debug = {
{debug}}
[other]
name = {
{others:name}}
[rcmd_parse]
time = @>@ Sys.Date() @<@
[bash_parse]
home = #>#echo $HOME#<#
[mulitple_parse]
multi = @>@str_replace('config','g$','gr')@<@, #>#echo configr#<#, {
{others:name}}
[glue_parse]
range_chr = !!glue {1:10}
range_num = !!glue_numeric {1:10}
在 other.ini
中添加如下内容
[others]
name = Tom
读取并解析
conf <- read.config("demo.ini", extra.list = list(debug = "true"),
other.config = "other.ini", rcmd.parse = TRUE,
bash.parse = TRUE, glue.parse = TRUE)
str(conf)
# List of 6
# $ DEFAULT :List of 1
# ..$ debug: chr "true"
# $ other :List of 1
# ..$ name: chr "Tom"
# $ rcmd_parse :List of 1
# ..$ time: chr "2022-10-07"
# $ bash_parse :List of 1
# ..$ home: chr "/Users/dengxsh"
# $ mulitple_parse:List of 1
# ..$ multi: chr "configr, configr, Tom"
# $ glue_parse :List of 2
# ..$ range_chr: chr [1:10] "1" "2" "3" "4" ...
# ..$ range_num: num [1:10] 1 2 3 4 5 6 7 8 9 10
写入文件
一般情况下,都是手动创建配置文件,很少会将数据直接写入到配置文件中,除非需要自动化创建默认的配置文件。我们可以将 list
对象写入到配置文件中,例如
data <- list(
user = list(username = "admin", passwd = "123456"),
info = list(type = "init")
)
write.config(config.dat = data, file.path = "test.ini", write.type = "ini")
在 test.ini
中将会看到如下内容
[user]
username=admin
passwd=123456
[info]
type=init
Python 解析文件
在 Python
中,我们可以使用标准库中的 configparser
包来解析 ini
格式的配置文件。例如,创建如下名为 setting.ini
的配置文件
[default]
path = /default/path
[server]
address = 127.0.0.1
port = 8080
导入包并创建配置解析器
import configparser
config = configparser.ConfigParser()
使用配置解析器来读取配置文件
config.read('setting.ini')
# ['setting.ini']
config.sections() # 获取所有 section
# ['default', 'server']
config['default']['path'] # 获取属性值
# '/default/path'
我们可以将配置解析器当做字典来使用,其具有字典的一般行为,但也存在一些差异。例如,解析器支持同时传入 section
和属性名称来获取属性值。
配置解析器并不会自动推测配置文件中值的类型,总是将它们存储为字符串,我们可以手动转换或使用解析器提供的便捷函数
config['server'].get('port')
# '8080'
int(config.get('server', 'port'))
# 8080
config.getint('server', 'port')
# 8080
除了 getint
之外,还有 getfloat
和 getboolean
,get
函数也可以提供默认值。
config['server'].get('name', 'Tom')
# 'Tom'
该解析器也支持一些特性,例如
- 支持冒号
:
声明键值对 - 支持配置文件内插值,值可以在被
get
调用返回之前进行预处理
我们在配置文件中 setting.ini
添加如下内容
[Paths]
home_dir: /Home/user
my_dir: %(home_dir)s/my
my_pictures: %(my_dir)s/Pictures
percent: 80%%
其中 %(home_dir)s
将会替换为 home_dir
属性的值,%%
会替换为百分号 %
config.read('setting.ini')
config.sections()
# ['default', 'server', 'Paths']
config.get('Paths', 'my_dir')
# '/Home/user/my'
config.get('Paths', 'my_pictures')
# '/Home/user/my/Pictures'
config.get('Paths', 'percent')
# '80%'
自定义解析器
ini
格式的变种非常多,默认的解析器只具备一些常用的功能,我们可以在创建解析器是指定一些行为。例如
allow_no_value
参数可用于指明是否接受不带值的属性delimiters
用于指定分隔键