📊 第3章 Pandas 入门
📄 一句话概括

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 秒实验

  1. 把 csv 的 encoding 强制写成 'gbk' 再读,看中文变成什么。
  2. 把 txt 的 sep 改成 ',' 读一次,看 shape 怎么变。
  3. 想一想:网页里如果两张表,read_html 返回的列表长度是几?怎么挑第二张?

常见误区

  1. Excel 另存的 csv 不写 encoding:出来全是乱码,以为文件坏了。
  2. 以为有 read_txt:没有,txt 一律用 read_csv 加 sep。
  3. sep 用默认的逗号去读制表符文件:整行挤成一列,还以为数据只有一列。
  4. read_html 直接传网址字符串:有些站点要 headers,抓回来是空列表或广告表。
自测三问(点开对答案) 1. 读 csv 中文乱码,第一步做什么? —— 加 encoding='gbk'(或 gb18030)再读一次。Excel 另存的 csv 在中文 Windows 上是 GBK。 2. 为什么 read_html 返回列表而不是 DataFrame? —— 一个页面可能有多张表,它把找到的都返回,由调用的人挑。 3. 怎么一眼判断读文件失败了? —— 看 shape。列数明显不对(比如该 6 列只有 1 列),就是分隔符或表头的问题。

数据读进来了。接下来三篇讲怎么从这张表里把想要的行和列挑出来。

相关笔记