柚子快報(bào)邀請(qǐng)碼778899分享:網(wǎng)絡(luò)爬蟲 —— 配置文件解析
柚子快報(bào)邀請(qǐng)碼778899分享:網(wǎng)絡(luò)爬蟲 —— 配置文件解析
網(wǎng)絡(luò)爬蟲 —— 配置文件解析
ini
ini( Initialization File )顧名思義,主要用于初始化應(yīng)用程序。這是一種無固定標(biāo)準(zhǔn)格式的配置文件,且文件沒有固定的后綴,常見的有 .ini、 .conf、.cfg,甚至還可以是 .txt。主要用于 Windows 操作系統(tǒng)上,但也有很多程序會(huì)采用 INI 文件作為配置文件使用。
文件格式
ini 格式在不同的解析器中會(huì)具有不同的特征,比較固定的是:
節(jié):使用中括號(hào)包裹的字符串,其后面的所有參數(shù)(到下一個(gè)小結(jié)的開始之前),都?xì)w屬于該節(jié)
[section]
參數(shù):以鍵值對(duì)的方式設(shè)置參數(shù)值,即程序中需要訪問的參數(shù)所對(duì)應(yīng)的值
name = value
注釋:以 ; 或 # 開頭的行表示的是注釋信息
; comment text
# comment line
大小寫不敏感section 中的參數(shù)順序與其在文件中出現(xiàn)的順序無關(guān)
除了上面的基本特征之外,不同的解析器可能還提供了
全局屬性冒號(hào)(:)或空格分隔的鍵值對(duì)聲明方式層次或嵌套形式的 section重復(fù)參數(shù)名稱參數(shù)引用等
示例
在 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 種配置文件,該包是對(duì) ini、jsonlite、yaml 和 RcppTOML 這 4 個(gè)包的封裝,內(nèi)核還是通過調(diào)用它們來對(duì)不同格式的文件進(jìn)行解析的。
首先需要安裝該包
# CRAN
install.packages('configr')
# Github
# install.packages("devtools")
devtools::install_github("Miachol/configr")
導(dǎo)入包
library(configr) # version 0.3.5
讀取文件
使用 read.config 函數(shù)即可讀取文件
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"
該函數(shù)返回一個(gè)嵌套的 list 對(duì)象,第一層為節(jié),第二層為參數(shù)值??梢栽诔绦蛑幸栽L問 list 的形式獲取配置文件中的參數(shù)信息。
該解析器提供了一些額外的特征,通過預(yù)先在文件中設(shè)置一些占位符,并在占位符中添加相應(yīng)的命令,然后在讀取時(shí)進(jìn)行解析。主要通過幾個(gè)參數(shù)來控制
參數(shù)功能extra.list用字符串 list 來替換 {{}} 包裹的字符other.config導(dǎo)入其他配置文件rcmd.parse是否將 @>@ 包裹的字符串作為 R 命令執(zhí)行bash.parse是否將 #># 包裹的字符串作為 bash 命令執(zhí)行g(shù)lue.parse是否執(zhí)行 glue 命令glue.flag設(shè)置 glue 命令的起始標(biāo)志,默認(rèn)為 !!glue
demo.ini 文件里面寫入如下內(nèi)容
[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 中添加如下內(nèi)容
[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
寫入文件
一般情況下,都是手動(dòng)創(chuàng)建配置文件,很少會(huì)將數(shù)據(jù)直接寫入到配置文件中,除非需要自動(dòng)化創(chuàng)建默認(rèn)的配置文件。我們可以將 list 對(duì)象寫入到配置文件中,例如
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 中將會(huì)看到如下內(nèi)容
[user]
username=admin
passwd=123456
[info]
type=init
Python 解析文件
在 Python 中,我們可以使用標(biāo)準(zhǔn)庫(kù)中的 configparser 包來解析 ini 格式的配置文件。例如,創(chuàng)建如下名為 setting.ini 的配置文件
[default]
path = /default/path
[server]
address = 127.0.0.1
port = 8080
導(dǎo)入包并創(chuàng)建配置解析器
import configparser
config = configparser.ConfigParser()
使用配置解析器來讀取配置文件
config.read('setting.ini')
# ['setting.ini']
config.sections() # 獲取所有 section
# ['default', 'server']
config['default']['path'] # 獲取屬性值
# '/default/path'
我們可以將配置解析器當(dāng)做字典來使用,其具有字典的一般行為,但也存在一些差異。例如,解析器支持同時(shí)傳入 section 和屬性名稱來獲取屬性值。
配置解析器并不會(huì)自動(dòng)推測(cè)配置文件中值的類型,總是將它們存儲(chǔ)為字符串,我們可以手動(dòng)轉(zhuǎn)換或使用解析器提供的便捷函數(shù)
config['server'].get('port')
# '8080'
int(config.get('server', 'port'))
# 8080
config.getint('server', 'port')
# 8080
除了 getint 之外,還有 getfloat 和 getboolean,get 函數(shù)也可以提供默認(rèn)值。
config['server'].get('name', 'Tom')
# 'Tom'
該解析器也支持一些特性,例如
支持冒號(hào) : 聲明鍵值對(duì)支持配置文件內(nèi)插值,值可以在被 get 調(diào)用返回之前進(jìn)行預(yù)處理
我們?cè)谂渲梦募?setting.ini 添加如下內(nèi)容
[Paths]
home_dir: /Home/user
my_dir: %(home_dir)s/my
my_pictures: %(my_dir)s/Pictures
percent: 80%%
其中 %(home_dir)s 將會(huì)替換為 home_dir 屬性的值,%% 會(huì)替換為百分號(hào) %
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 格式的變種非常多,默認(rèn)的解析器只具備一些常用的功能,我們可以在創(chuàng)建解析器是指定一些行為。例如
allow_no_value 參數(shù)可用于指明是否接受不帶值的屬性delimiters 用于指定分隔鍵和值的子字符串comment_prefixes 注釋的前綴interpolation 用于指定插值方式,可以使用 ExtendedInterpolation 類指定更高級(jí)的語法,或使用 None 來禁用插值語法
擴(kuò)展插值插值可以跨越多個(gè)層級(jí),使用方式形如 ${section:option},如果省略 section:,則表示作用于當(dāng)前小節(jié)。例如,對(duì)如下配置文件進(jìn)行解析
[default]
path = /Home/user
[Paths]
my_dir: ${default:path}/my
my_pictures: ${my_dir}/Pictures
[Others]
money: $$80
config = configparser.ConfigParser(
interpolation=configparser.ExtendedInterpolation()
)
config.read('setting.ini')
config.get('Paths', 'my_dir')
# '/Home/user/my'
config.get('Others', 'money')
# '$80'
寫入文件
我們可以使用類似于為字典賦值的方式,為解析器添加配置,例如
config['Others'] = {
'name': 'Tom',
'age': 28
}
config['default']['salary'] = '10000'
寫出解釋器對(duì)象的值
with open('setting.ini', 'w') as configfile:
config.write(configfile)
setting.ini 中的內(nèi)容將變?yōu)?/p>
[default]
path = /Home/user
salary = 10000
[Paths]
my_dir = ${default:path}/my
my_pictures = ${my_dir}/Pictures
[Others]
name = Tom
age = 28
json
json(JavaScript Object Notation)是一種開放的標(biāo)準(zhǔn)文件格式,易于機(jī)器創(chuàng)建和解析,是一種實(shí)用的輕量級(jí)數(shù)據(jù)交換格式。雖然它起源于 JavaScript,但它獨(dú)立于 JavaScript,現(xiàn)在很多語言都提供了相應(yīng)的包來用于處理這種類型的數(shù)據(jù)。一些生物數(shù)據(jù)庫(kù)也會(huì)將數(shù)據(jù)存儲(chǔ)為 json 格式,便于解析。
文件格式
json 文件的格式包含兩種,可以理解為將 Python 中的字典或列表直接存儲(chǔ)到文件中,例如
字典形式的文件格式(dict.json)
{
"name": ["John"],
"age": [19],
"children": ["Catherine", "Thomas", "Trevor"]
}
列表形式的文件格式(list.json)
[
{"name": "Tom", "age": 18},
{"name": "Jim", "age": 20}
]
R 解析文件
R 中有幾個(gè)用于解析 json 的包,上面的 configr 也可以,使用方法一樣,只需將文件類型參數(shù)改為 json 即可
read.config("dict.json", file.type = "json")
讀取 json 文件時(shí),會(huì)根據(jù) json 里面的數(shù)據(jù)內(nèi)容自動(dòng)將其轉(zhuǎn)換為 list 或 data.frame 類型,例如
j <- read.config("Downloads/dict.json", file.type = "json")
str(j)
# List of 3
# $ name : chr "John"
# $ age : int 19
# $ children: chr [1:3] "Catherine" "Thomas" "Trevor"
read.config("Downloads/list.json", file.type = "json")
# name age
# 1 Tom 18
# 2 Jim 20
可以將 list 或 data.frame 數(shù)據(jù)轉(zhuǎn)換為 json 對(duì)象,pretty 參數(shù)用于控制是否美化輸出
d <- data.frame(
name = c("Tom", "Jim"),
age = c(18, 20)
)
write.config(d, "Downloads/list.json", write.type = "json")
# [1] TRUE
Python 解析文件
Python 標(biāo)準(zhǔn)庫(kù)提供了 json 包可以用于處理 json 數(shù)據(jù),可以將文件其轉(zhuǎn)換為內(nèi)置的 list 或 dict 類型對(duì)象。
使用 load 函數(shù)導(dǎo)入文件對(duì)象中的數(shù)據(jù)
import json
json.load(open("dict.json"))
# {'name': 'John', 'age': 19, 'children': ['Catherine', 'Thomas', 'Trevor']}
或者使用 dump 函數(shù)將數(shù)據(jù)寫入到文件中
data = [
{"name": "Tom", "age": 18},
{"name": "Jim", "age": 20}
]
json.dump(data, open('list.json', 'w'))
可直接將字典或列表數(shù)據(jù)寫入文件中,導(dǎo)入數(shù)據(jù)時(shí)也會(huì)自動(dòng)解析為字典或列表類型的對(duì)象。這兩個(gè)函數(shù)分別有一個(gè)加 s 的版本,用于處理對(duì)象與字符串之間的轉(zhuǎn)換,如
json.dumps(data)
# '[{"name": "Tom", "age": 18}, {"name": "Jim", "age": 20}]'
d = '{"name": "John", "age": 19, "children": ["Catherine", "Thomas", "Trevor"]}'
json.loads(d)
# {'name': 'John', 'age': 19, 'children': ['Catherine', 'Thomas', 'Trevor']}
注意,將 json 格式的字符串轉(zhuǎn)換為對(duì)象,其中的字符串需要為雙引號(hào)。同時(shí),在轉(zhuǎn)換時(shí)也可以設(shè)置輸出格式,設(shè)置縮進(jìn)的空格數(shù) (indent),或者對(duì)鍵進(jìn)行排序(sort_keys)
j = json.dumps(data, indent=4, sort_keys=True)
print(j)
# [
# {
# "age": 18,
# "name": "Tom"
# },
# {
# "age": 20,
# "name": "Jim"
# }
# ]
yaml
YAML(Yet Another Markup Language) 是一種數(shù)據(jù)序列化的語言,以數(shù)據(jù)為中心,且更注重于數(shù)據(jù)的描述和展示。其可讀性高、易于理解,可靈活地與其他編程語言結(jié)合使用。相較于前面兩種文件格式,其既可以定義復(fù)雜的結(jié)構(gòu)化數(shù)據(jù),也支持注釋、屬性引用等,還可以引用其他配置文件,降低代碼的冗余。
基本語法
yaml 中數(shù)據(jù)類型的概念與其他高級(jí)編程語言類似,包括三種數(shù)據(jù)類型
數(shù)組(列表)映射(字典或哈希)標(biāo)量(包括字符串、整數(shù)和浮點(diǎn)數(shù)等)。
yaml 是大小寫敏感的,使用與 Python 類似的縮進(jìn)(使用空格而不是 TAB 控制縮進(jìn))來表示數(shù)據(jù)的層級(jí)關(guān)系(一般不使用括號(hào)或引號(hào))、鍵值對(duì)使用冒號(hào)作為分隔標(biāo)識(shí)(冒號(hào)后面必須緊跟一個(gè)空格)、# 符號(hào)之后的內(nèi)容作為注釋不會(huì)被解析。文件后綴推薦使用 .yaml,也有人會(huì)使用 .yml 作為文件后綴。
其與 json 格式非常類似,可以認(rèn)為是 json 的超集,在 yaml 文件中也可以使用 json 的語法。
例如,我們定義如下關(guān)系映射數(shù)據(jù)
server: # web server
name: work
host: 127.0.0.1
port: 8080
注意,縮進(jìn)的空格數(shù)沒有限制,只要保證同一層級(jí)中所有的元素左對(duì)齊即可。上面的內(nèi)容將被解析為
{'server': {'name': 'work', 'host': '127.0.0.1', 'port': 8080}}
上面文件的內(nèi)容也可以寫在一行,但需要使用花括號(hào)包裹起來
server: {name: work, host: 127.0.0.1, port: 8080}
數(shù)組使用橫杠 - 標(biāo)識(shí)每一個(gè)元素(橫杠后面必須緊跟一個(gè)空格),例如
address_list:
- 127.0.0.1
- 192.168.0.1
- 0.0.0.0
上面的內(nèi)容將被解析為
{'address_list': ['127.0.0.1', '192.168.0.1', '0.0.0.0']}
列表也可以寫在一行內(nèi),但是需要用方括號(hào)包裹起來
address_list: [127.0.0.1, 192.168.0.1, 0.0.0.0]
如果要在一個(gè)文件中編寫多個(gè)文檔,可以使用三橫杠 --- 來標(biāo)識(shí)文檔的開始,三個(gè)點(diǎn) ... 來標(biāo)識(shí)文檔的結(jié)束。例如
---
name: Sam
age: 20
weight: 60kg
...
---
name: Ban
age: 21
weight: 55kg
...
在 yaml 文件中,字符串并不需要用使用引號(hào),如果存在轉(zhuǎn)義字符可以用雙引號(hào)將字符串包裹,而單引號(hào)只能用兩個(gè)單引號(hào)來轉(zhuǎn)義自身,即 'don''t' 會(huì)被解析為 "don't"。而對(duì)于多行文本,有兩個(gè)字符可以指定不同的行為
|:多行內(nèi)容之間保留插入的換行符>:多行內(nèi)容之間使用空格連接
preserve: |
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
fold: >
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
兩種模式中字符串將被解析為
{'preserve': 'Beautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\n',
'fold': 'Complex is better than complicated. Flat is better than nested. Sparse is better than dense.'
}
變量引用
如果要引用前面定義的變量,可以使用 & 先對(duì)元素進(jìn)行錨定,在需要引用的地方使用 * 來引用之前錨定的內(nèi)容,可以在錨定時(shí)指定相應(yīng)的名稱。例如
Sam:
name: Sam
age: &a 20
hobby:
- &s1 football
- sing song
Ben:
name: Ben
age: *a
hobby:
- *s1
對(duì)于鍵值對(duì)映射的元素需要在冒號(hào)之后添加錨定,對(duì)于列表元素,則在值之前添加錨定。
錨定與合并標(biāo)簽(<<)搭配使用,可以將任意數(shù)據(jù)進(jìn)行合并,例如
person: &base
name: null
age: 0
sam:
name: Sam
<<: *base # 引用錨點(diǎn),實(shí)例化時(shí)會(huì)自動(dòng)展開
hobby: # 添加額外的屬性
- football
tom:
<<: *base # 引用錨點(diǎn),實(shí)例化時(shí)會(huì)自動(dòng)展開
name: Tom # 覆蓋屬性,相同屬性是允許的但只會(huì)取最后一次的值
age: 10
上面的文件將被解析為
{
'person': {'name': None, 'age': 0},
'sam': {'name': 'Sam', 'age': 0, 'hobby': ['football']},
'tom': {'name': 'Tom', 'age': 10}
}
數(shù)據(jù)類型
一般我們讀取文件時(shí),會(huì)自動(dòng)解析數(shù)據(jù)的類型,我們也可以在文件中使用雙感嘆號(hào)加類型名稱的方式(如 !!str)強(qiáng)制轉(zhuǎn)換數(shù)據(jù)的類型,主要包含如下類型
標(biāo)記類型標(biāo)記類型!!int整數(shù)類型!!float浮點(diǎn)類型!!bool布爾類型!!str字符串類型!!binary二進(jìn)制字符串!!timestamp日期時(shí)間類型!!null空值!!set集合類型!!omp,!!pairs配對(duì)列表!!map鍵值對(duì)!!seq列表
例如,對(duì)于下面的文件內(nèi)容
Stu: !!map
name: !!str Sam
age: !!float 20
boy: !!bool yes
Info: !!seq
- name
- age
- boy
將被解析為
{'Stu': {'name': 'Sam', 'age': 20.0, 'boy': True},
'Info': ['name', 'age', 'boy']}
R 解析文件
在 R 中操作 yaml 文件,也是使用 configr 包的 read.config 函數(shù)。對(duì)于如下文件 demo.yaml
- Sam:
age: 19
hobby:
- football
- sing song
- Tom:
age: 19
hobby:
- football
- TV
文件將會(huì)被解析為一個(gè) list,如果在讀取時(shí)拋出了 readLines 函數(shù)的警告信息,可以忽略,或者在文件最后一行添加一個(gè)空行即可。
y <- read.config("demo.yaml", file.type = "yaml")
str(y)
# List of 2
# $ :List of 1
# ..$ Sam:List of 2
# .. ..$ age : int 19
# .. ..$ hobby: chr [1:2] "football" "sing song"
# $ :List of 1
# ..$ Tom:List of 2
# .. ..$ age : int 19
# .. ..$ hobby: chr [1:2] "football" "TV"
與前面類似,也可以將一個(gè)數(shù)據(jù)框?qū)懗鰹?yaml 文件
write.config(d, "dump.yaml", write.type = "yaml")
dump.yaml 文件中的內(nèi)容為
name:
- Tom
- Jim
age:
- 18.0
- 20.0
Python 解析文件
在Python 中我們可以使用第三方包 PyYAML 來解析 yaml 文件,可直接使用 pip 進(jìn)行安裝
pip install pyyaml # version 6.0
如果文件中只有一個(gè)文檔,可以使用 load 函數(shù)或 safe_load
import yaml
from yaml import CLoader
yaml.load(open('demo.yaml'), CLoader)
# yaml.safe_load(open('demo.yaml'))
# [{'Sam': {'age': 19, 'hobby': ['football', 'sing song']}},
# {'Tom': {'age': 19, 'hobby': ['football', 'TV']}}]
如果一個(gè)文件里面有多個(gè)文檔,則需要使用 load_all,該函數(shù)將返回一個(gè)生成器
for data in yaml.load_all(open('demo.yaml'), CLoader):
print(data)
如果要將一個(gè)對(duì)象序列化為 yaml 文件,則可以使用 dump 函數(shù)
data = {
'name': 'Tom',
'age': 30,
'hobby': ['football', 'TV']
}
yaml.dump(data, open('dump.yaml', 'w'))
或者寫入多個(gè)文檔
yaml.dump_all([data, 1, 2, 3], open('dump.yaml', 'w'))
TOML
TOML(Tom's Obvious, Minimal Language) 的設(shè)計(jì)宗旨在于創(chuàng)建一種語義明確且易于閱讀的最精簡(jiǎn)配置文件格式,其語法有點(diǎn)類似于 INI 文件格式,但它加了更多的規(guī)范來進(jìn)行限定,這些規(guī)范包括一系列的數(shù)據(jù)類型:字符串、整數(shù)、浮點(diǎn)數(shù)、布爾值、日期時(shí)間、數(shù)組和表。其文件后綴為 .toml。
基本語法
與 yaml 類似,toml 也是大小寫敏感的,使用 # 來添加注釋,也是以鍵值對(duì)的形式來定義屬性,但是其不依賴縮進(jìn),且不屬于屬性名或?qū)傩灾档目崭穸紩?huì)被忽略掉。
鍵值對(duì)使用的是 = 來進(jìn)行聲明,例如
key = "value" # this is first comment
鍵名可以是裸露的或使用引號(hào)包裹的字符串,即可分為裸鍵和引號(hào)鍵。有效的裸鍵必須為字符集 A-Za-z0-9_- 中的字符組成,引號(hào)鍵可以定義更加廣泛的名稱。注意,裸鍵加引號(hào)與不加引號(hào)本質(zhì)是一樣的,會(huì)被當(dāng)做同一個(gè)屬性,且同一個(gè)鍵不能被重復(fù)賦值。
a-b = "123"
123 = "abc"
鍵名可以是空字符串,但是不推薦使用,也沒人會(huì)在實(shí)際項(xiàng)目中這么用。
鍵名中如果存在 . 號(hào),表示嵌套層級(jí),例如
person.name = 'Tom'
person.age = 20
person.'major' = 'chinese'
與下面的 json 表示同樣的內(nèi)容,會(huì)將 . 之后的名字作為子鍵名,與后面的表結(jié)構(gòu)所表示的內(nèi)容相似
{'person': {'name': 'Tom', 'age': 20, 'major': 'chinese'}}
字符串類型
字符串可分為 4 種類型,分別用不同的符號(hào)來表示:
基本字符串使用雙引號(hào)(")多行字符串使用三個(gè)雙引號(hào)(""")單行字面量使用單引號(hào)(')多行字面量使用三個(gè)單引號(hào)(''')
字符串的值只能是有效的 UTF-8 字符,例如
str1 = "abc\tbcd\n"
str2 = """
Beautiful is better than ugly. \
Explicit is better than implicit.
Simple is better than complex.
"""
打印字符串之后,轉(zhuǎn)移字符將會(huì)發(fā)揮作用,同時(shí)在多行字符串中,行尾的 \ 表示將兩行連接起來,即忽略后面的換行符。
abc bcd
Beautiful is better than ugly. Explicit is better than implicit.
Simple is better than complex.
對(duì)于字符串字面量
str3 = 'abc\tbcd\n'
str4 = '''
a\tb\ncd \
efg\nh
'''
所有字符不會(huì)被轉(zhuǎn)義,而是原樣輸出
abc\tbcd\n
a\tb\ncd \
efg\nh
整數(shù)類型
整數(shù)類型的數(shù)據(jù),可以使用 + 和 - 來標(biāo)識(shí)正負(fù)數(shù),如果是較大的數(shù)值,可以使用 _ 來分隔數(shù)字提高可讀性,也可以使用不同進(jìn)制形式的數(shù)值。例如
a = 3
b = 1_000 # 千分位分隔
c = 0xDEADBEEF # 十六進(jìn)制
d = 0o12345 # 八進(jìn)制
e = 0b101001 # 二進(jìn)制
文件將被解析為
{'a': 3, 'b': 1000, 'c': 3735928559, 'd': 5349, 'e': 41}
浮點(diǎn)類型
浮點(diǎn)類型的數(shù)值與整數(shù)類似,只是分為整數(shù)部分和小數(shù)部分,注意,兩部分都不能省略。也支持科學(xué)計(jì)數(shù)法,下劃線分隔等,例如
a = 3.1415
b = 2.1e12
c = inf
d = nan
e = 3.141_592_653
將被解析為
{'a': 3.1415, 'b': 2100000000000.0, 'c': inf, 'd': nan, 'e': 3.141592653}
布爾與時(shí)間日期
布爾類型使用小寫
a = true
b = false
時(shí)間日期格式
a = 09:32:03
b = 1997-07-01
c = 1941-08-14T08:23:10
在 Python 中會(huì)被解析為相應(yīng)的時(shí)間日期格式
{'a': datetime.time(9, 32, 3),
'b': datetime.date(1997, 7, 1),
'c': datetime.datetime(1941, 8, 14, 8, 23, 10)}
數(shù)組
這里的數(shù)據(jù)基本相當(dāng)于 Python 中的 list 類型,可以混合任意類型的數(shù)據(jù),元素之間多余的空格和換行都會(huì)被忽略。例如
ints = [1, 2, 3]
strs = ["a", "b"]
nest_arr = [
[1, 2],
[3, 4, 5]
]
mix = [0.1, 1, 'a', [2, "b"]]
解析為
{'ints': [1, 2, 3],
'strs': ['a', 'b'],
'nest_arr': [[1, 2], [3, 4, 5]],
'mix': [0.1, 1, 'a', [2, 'b']]}
哈希表
哈希表或字典類型,使用方括號(hào)里面加表名的方式作為表頭來聲明,與 ini 中的節(jié)類似,其作用范圍從該表頭至下一個(gè)表頭或文件結(jié)束。例如
[table]
name = "Tom"
age = 10
在 Python 中將被解析為嵌套字典
{'table': {'name': 'Tom', 'age': 10}}
表名可以像鍵名一樣,使用 . 來創(chuàng)建嵌套哈希表,例如
[table.person]
name = "Tom"
age = 10
解析為 table 表下面的 person 子表
{'table': {'person': {'name': 'Tom', 'age': 10}}}
表中的內(nèi)容通常放在一起定義,不能定義兩個(gè)同名的表。其實(shí)本質(zhì)上帶 . 的鍵名也是創(chuàng)建嵌套的表,會(huì)將最后一個(gè)點(diǎn)之前的名稱作為表名,并創(chuàng)建對(duì)應(yīng)的表,最后一個(gè)鍵作為屬性值。例如
table.person.chinese.fujian = '123'
會(huì)創(chuàng)建三個(gè)表,table 表里面包含 person 表,person 表里面包含 chinese 表
表的內(nèi)容也可以寫在同一行中,即內(nèi)聯(lián)表,將所有內(nèi)容以一種緊湊的形式展現(xiàn),類似于 json
[table]
person = {name='Tom', age=19}
{'table': {'person': {'name': 'Tom', 'age': 19}}}
內(nèi)聯(lián)表也可以作為數(shù)組中的元素
human = [{name='Tom', age=11}, {name='Sam', age=20}]
{'human': [{'name': 'Tom', 'age': 11}, {'name': 'Sam', 'age': 20}]}
表數(shù)組
顧名思義,即由表組合起來的數(shù)組,使用雙方括號(hào)里面加表名的方式聲明下面的表內(nèi)容將作為數(shù)組中的一個(gè)元素,其中表名將作為數(shù)組的鍵,例如
[[table]]
name = 'T1'
[[table.subtable]]
name = 'ST1'
[[table.subtable]]
name = 'ST2'
[[table]]
name = 'T2'
被解析為
{'table': [
{'name': 'T1', 'subtable': [
{'name': 'ST1'}, {'name': 'ST2'}
]},
{'name': 'T2'}]
}
R 解析文件
我們前面使用的 configr 包只能讀取 toml 文件,而無法寫入,所以我們使用另一個(gè)包 blogdown,首先對(duì)包進(jìn)行安裝
install.packages('blogdown') # 1.13
blogdown::install_hugo()
安裝成功后,讀取 demo.toml 文件
[table.person]
name = "Tom"
age = 10
直接使用包名加兩個(gè)冒號(hào)來訪問包內(nèi)的函數(shù),可以不用導(dǎo)入包,
blogdown::read_toml("demo.toml")
# $table
# $table$person
# $table$person$age
# [1] 10
#
# $table$person$name
# [1] "Tom"
將數(shù)據(jù)寫入到文件中
data <- list(
name = 'Tom',
age = 30,
hobby = c('football', 'TV')
)
blogdown::write_toml(data, "dump.toml")
Python 解析文件
在 Python 中用于解析 toml 文件的包比較多,如 toml、rtoml、qtoml、tomli、tomlkit 等,由于 Python 3.11 標(biāo)準(zhǔn)庫(kù)中加入的 tomllib 包是從 tomli 包而來,所以我們使用 tomli 包來解析 toml 文件,保持兼容
安裝包
pip install tomli # version 2.0.1
解析文件,需要以二進(jìn)制的方式打開文件
import tomli
tomli.load(open('demo.toml', 'rb'))
# {'table': {'person': {'name': 'Tom', 'age': 10}}}
tomli 是一個(gè)只讀取并解析文件的包,若要將數(shù)據(jù)寫入到 toml 文件中,需要用到其對(duì)應(yīng)的寫入數(shù)據(jù)的版本 tomli_w
pip install tomli-w # version 1.0.0
寫入文件中
import tomli_w
data = {
'name': 'Tom',
'age': 30,
'hobby': ['football', 'TV']
}
tomli_w.dump(data, open('dump.toml', 'wb'))
柚子快報(bào)邀請(qǐng)碼778899分享:網(wǎng)絡(luò)爬蟲 —— 配置文件解析
相關(guān)閱讀
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。