csv 和 txt 都走 read_csv,成败只看两个参数:encoding 和 sep。 网页表格走 read_html,返回的是列表,因为一个页面可能有好几张表。 四种来源读进来都是 DataFrame,进去之后的操作完全一样。
上一篇只解决了 xlsx。这一篇把 csv、txt、网页三种来源一次收齐。 本机装了 lxml 和 html5lib,read_html 能真跑;材料是一段自己写的 HTML 表格。
一、csv:两个参数决定成败
pd.read_csv("成绩表.csv"),一行读进来,shape 是 (10, 6)。
encoding 管中文:编码给错,读进来是一堆问号或方块,但不报错。
sep 管分列:分隔符给错,整行挤成一列,shape 会变成 (10, 1)。
这两个参数错了,表照样读得出,只是内容全错。所以读完必须看 shape。
二、编码这件事,说到底就三个值
| 来源 | encoding 写什么 | 为什么 |
|---|---|---|
| Python 自己写的 csv | 不用写 | 默认 utf-8 |
| 带 BOM 的 csv | 不用写 | BOM 头会自报编码 |
| Excel 另存的 csv | 'gbk' 或 'gb18030' | Windows 中文默认 GBK |
本机写这份 csv 时用了 utf-8-sig,多写了一个 BOM 头,读的时候不指定也能认。
而 Excel 里点「另存为 csv」,出来的是 GBK。这时候不写 encoding='gbk' 就是乱码。
分辨办法很简单:直接读一次,中文是乱码就说明编码不对,换 gbk 再试。
gb18030 是 gbk 的超集,生僻字多的时候用它更保险。
三、txt:跟 csv 只差一个分隔符
制表符分隔的文本,sep='\t' 一给就读对,shape 也是 (10, 6)。
逗号分隔就是 sep=',',分号分隔就是 sep=';'——txt 没有标准,全看写的人。
sep 猜错的症状很明确:shape 变成 (10, 1),六列数据全塞进第一列。
shape 是检查读取是否成功最快的手段。列数不对,就是分隔符或表头的问题。
四、网页表格:read_html
pd.read_html(html) 返回一个列表——一个页面可能有好几张表,它全抓回来。
这次找到 1 张,取 [0] 就是那张 DataFrame。
| 城市 | 销量 |
|---|---|
| 武汉 | 120 |
| 宜昌 | 86 |
它依赖 lxml 或 html5lib 解析,本机两个都装了。没装的话报 ImportError,装上就好。 read_html 只认 table 标签。现在很多网页用 div 拼表格,那种它抓不到,得上爬虫。
五、四种来源对照
| 来源 | 函数 | 最要紧的参数 |
|---|---|---|
| .xlsx | read_excel | sheet_name、usecols |
| .csv | read_csv | encoding、sep |
| .txt | read_csv | sep |
| 网页 | read_html | match(挑哪张表) |
注意 txt 走的是 read_csv,不是 read_txt——Pandas 里没有这个函数。
四个函数的返回值都是 DataFrame。进去之后的操作完全一样,不用为每种来源学一套。
六、动手 Demo:csv、txt 和网页表格
先写一份 csv(带 BOM)和一份制表符分隔的 txt,再写一段 HTML 表格。 三种来源各读一遍,最后拼一张对照表。
import io
import pandas as pd
CSV = "成绩表.csv"
print("csv %s" % (pd.read_csv(CSV).shape,))
print("txt %s" % (pd.read_csv("成绩表.txt", sep="\t").shape,))
raw = "姓名,班级\n张伟,一班\n王芳,一班\n"
print("sep 写错 %s" % (pd.read_csv(io.StringIO(raw), sep="\t").shape,))
html = "<table><tr><th>城市</th><th>销量</th></tr>" \
"<tr><td>武汉</td><td>120</td></tr>" \
"<tr><td>宜昌</td><td>86</td></tr></table>"
tables = pd.read_html(io.StringIO(html))
print("网页表 %d 张" % len(tables))
print(tables[0].to_string(index=False))
实跑输出:
--------------------------------------------------------------------
csv、txt 和网页表格
--------------------------------------------------------------------
① csv:两个参数决定成败
--------------------------------------------------------------------
直接读,shape 是 (10, 6)。
两个参数最要紧:encoding 和 sep。编码错了中文变乱码,分隔符错了整行挤成一列。
本机写 csv 时用了 utf-8-sig,读的时候不用指定也能认——因为 BOM 头会告诉它。
! Windows 上从 Excel 另存的 csv 常是 gbk 编码,读的时候要写 encoding='gbk'。
② txt:跟 csv 只差一个分隔符
--------------------------------------------------------------------
制表符分隔的文本,sep='\t' 就读对了,shape 是 (10, 6)。
如果 sep 猜错,整行会变成一列:shape 会变成 (10, 1),一眼就能发现。
! shape 是检查读取是否成功最快的手段:列数不对,就是分隔符或表头的问题。
③ 网页表格:read_html
--------------------------------------------------------------------
read_html 返回的是一个列表,因为一个网页可能有好多张表。这次找到 1 张。
| 行 | 城市 | 销量 |
|---|---:|---:|
| 0 | 武汉 | 120 |
| 1 | 宜昌 | 86 |
它依赖 lxml 或 html5lib,本机两个都装了。没装的话会报 ImportError。
! read_html 只抓 table 标签。现在的网页多半用 div 画表格,抓不到——那种要上爬虫。
④ 四种来源对照
--------------------------------------------------------------------
| 来源 | 函数 | 最要紧的参数 |
|---|---|---|
| .xlsx | read_excel | sheet_name、usecols |
| .csv | read_csv | encoding、sep |
| .txt | read_csv | sep |
| 网页 | read_html | match(选哪张表) |
四个函数的返回值都是 DataFrame,读进来之后的操作完全一样。
! 所以不用为每种来源学一套:学一次 DataFrame 操作,四种来源通用。
read_html 传字符串会报 OSError,要包一层 io.StringIO——它要的是「文件」,不是「内容」。
sep 写错的症状是 shape 从 (10, 6) 变成 (10, 1),一眼就能认出来,比报错好查。
30 秒实验
- 把 csv 的 encoding 强制写成 'gbk' 再读,看中文变成什么。
- 把 txt 的 sep 改成 ',' 读一次,看 shape 怎么变。
- 想一想:网页里如果两张表,
read_html返回的列表长度是几?怎么挑第二张?
常见误区
- Excel 另存的 csv 不写 encoding:出来全是乱码,以为文件坏了。
- 以为有 read_txt:没有,txt 一律用 read_csv 加 sep。
- sep 用默认的逗号去读制表符文件:整行挤成一列,还以为数据只有一列。
- read_html 直接传网址字符串:有些站点要 headers,抓回来是空列表或广告表。
自测三问(点开对答案)
1. 读 csv 中文乱码,第一步做什么? —— 加 encoding='gbk'(或 gb18030)再读一次。Excel 另存的 csv 在中文 Windows 上是 GBK。 2. 为什么 read_html 返回列表而不是 DataFrame? —— 一个页面可能有多张表,它把找到的都返回,由调用的人挑。 3. 怎么一眼判断读文件失败了? —— 看 shape。列数明显不对(比如该 6 列只有 1 列),就是分隔符或表头的问题。数据读进来了。接下来三篇讲怎么从这张表里把想要的行和列挑出来。
- ☐ (本篇完,下一篇 3.8 抽取行:head、loc 与 iloc)