最近领导给了一个任务,从单位的数据库里面导出所有的数据,存到本地excel表格。我就想,这不挺简单的么,给我数据库的密码账户,几条语句搞定。
结果让人大失所望,单位数据库只能通过后台管理系统查看,平台压根不提供批量导出功能,至于数据库直接访问什么的,更是想都别想,大领导不给批。
所以,只能采取笨办法了,网络爬虫给爬下来!
于是乎,重拾丢弃了大半年的python。开始钻研如何写一个简单的小爬虫。
python写爬虫的思路其实很简单。下面简单说下
1)python模拟登录。主要是获取cookie~
2)分析与平台交互过程中http包所含的数据特点。主要就是请求和响应。
这个平台诡异的地方在于,要想提取数据,并不是一次到位。首先,得获取大的列表,列表会有分页,然后,点进列表中的每一项查看详情。
通过对来往http包的分析,其流程大致如下:
模拟登录->发起获取列表请求(post, json)->返回列表数据(json)->发起获取详情请求(get)->返回详情页面(html)
完整的数据需要拼合列表数据和详情页面数据。前者,只需解析json数据既可,但是后面的详情页面,得对html页面进行解析,提取所需项。
流程并不复杂,但是写起来坑却太多。此文着力记录踩过的坑。主要是两大坑。
坑No1:蛋疼的python编码方式
这个坑可以分为几个小问题来解答
1)unicode和utf-8是什么关系?
这个问题,知乎上有一句话解释挺好的,那就是:utf8是对unicode字符集进行编码的一种编码方式。
unicode字符集本身是一种映射,它将每一个真实世界的字符与某一数值联系在一起,是一种逻辑关系。utf-8则是编码方式,是对unicode所代表的值进行编码的算法。
简单地说,就是:字符->unicode->utf-8
例如:中文“你好” -> \u4f60\u597d -> \xe4\xbd\xa0\xe5\xa5\xbd
2)str和unicode又是什么关系?
str和unicode是python2.X里面的概念。
例如 s=u‘你好‘
s变量就是一个unicode字符串,是一个unicode对象(type(s) == unicode)
其中len(s) = 2
存储的值为\u4f60\u597d。
至于str,则是python最原始的数据流。可以理解为字节流,即二进制码。
Python has two different datatypes. One is ‘unicode‘ and other is ‘str‘.
Type ‘unicode‘ is meant for working with codepoints of characters.
Type ‘str‘ is meant for working with encoded binary representation of characters.
以上述“你好”为例,其unicode是\u4f60\u597d。这个值还可以进行一次utf-8的编码,最终成为存储的字节流,也就是\xe4\xbd\xa0\xe5\xa5\xbd
在python3中,所有的str都变成了unicode,3中bytes则替代了2.X中的str
stackoverflow有一个解答说的挺好http://stackoverflow.com/questions/18034272/python-str-vs-unicode-types
unicode
, which is python 3‘s str
, is meant to handle text. Text is a sequence of code points whichmay be bigger than a single byte. Text can be encoded in a specific encoding to represent the text as raw bytes(e.g. utf-8
, latin-1
...). Note that unicode
is not encoded! The internal representation used by python is an implementation detail, and you shouldn‘t care about it as long as it is able to represent the code points you want.
On the contrary str
is a plain sequence of bytes. It does not represent text! In fact, in python 3 str
is called bytes
.
You can think of unicode
as a general representation of some text, which can be encoded in many different ways into a sequence of binary data represented via str
.
Note that using str
you have a lower-level control on the single bytes of a specific encoding representation, while using unicode
you can only control at the code-point level.
如此,便很明了了~
3)encode和decode的使用方法。
有了上述两点的基础,这里的使用方法就不难了。
所谓encode,就是unicode->str,有意义的文字,变为字节流。
而decode,就是str->unicode,字节流,变为有意义的文字。
decode对str使用,encode对unicode使用。
例如:
u_a=u‘你好‘ #这里是unicode字符 u_a #输出u‘\u4f60\u597d‘ s_a = u_a.encode(‘utf-8‘) #对u_a进行utf-8编码,转化为字节流 s_a #输出‘\xe4\xbd\xa0\xe5\xa5\xbd‘ u_a_ = s_a.decode(‘utf-8‘) #对s_a进行utf-8解码,还原为unicode u_a_ #输出u‘\u4f60\u597d‘
utf-8是一种编码方法,此外,常见的还有gbk等等。
4)#coding:utf-8和setdefaultencoding有什么区别?
#coding:utf-8作用是定义源代码的编码,如果没有定义,此源码中不可以包含中文字符。
setdefaultencoding是python代码在执行时,unicode类型数据默认的编码方式。(Set the current default string encoding used by the Unicode implementation.)这是因为,unicode有很多编码方式,包括UTF-8、UTF-16、UTF-32,中文还有gbk。在调用decode和encode函数时,在不显示指定参数的情况下,就会采用上述默认的编解码方式。
需要注意的是,在windows下的idle中,在不显式指出u前缀的前提下,会默认采用gbk编码。
下面看一个例子:
a = ‘你好‘ #在windows下的idle里面,a是gbk编码 a #输出‘\xc4\xe3\xba\xc3‘ 这是gbk b = a.decode(‘gbk‘) #进行gbk解码为unicode b #输出u‘\u4f60\u597d‘ print b #输出 你好 b = a.decode() #在不指定参数情况下,默认采用ascii编解码,此时会报错, #UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte a = u‘你好‘ b = a.encode() #同理,也会报错 #UnicodeEncodeError: ‘ascii‘ codec can‘t encode characters
坑No2:繁杂的正则表达式(待续)