简介
最近读了这本书,做些记录。本书用的是Python3,我习惯用2,有些地方不能用2再用3。有些章节对我作用不大,或者只是一个较粗略的介绍,会略过不记。
创建爬虫
解析HTML
urllib与urllib2
在很多地方看到urllib和urllib2互用urlopen,但实际上urllib2是urllib的进一步封装,在很多地方也有区别:
- urllib2可以接受一个Request类的实例来设置URL请求的headers,urllib仅可以接受URL。这意味着,你不可以通过urllib模块伪装你的User Agent字符串等(伪装浏览器)。
- urllib提供urlencode方法用来GET查询字符串的产生,而urllib2没有。这是为何urllib常和urllib2一起使用的原因。
- urllib2模块比较优势的地方是urlliburllib2.urlopen可以接受Request对象作为参数,从而可以控制HTTP Request的header部。
- 但是urllib.urlretrieve函数以及urllib.quote等一系列quote和unquote功能没有被加入urllib2中,因此有时也需要urllib的辅助。
BeautifulSoup
bs0bj = BeautifulSoup(html.read())
获得一个BS对象后,可以
通过结点访问,如:
1
2
3
4
5
6bs0bj.h1
bs0bj.html.body.h1
bs0bj.body.h1
获取属性:
bs0bj.h1.attrs["src"]通过tag的属性
1
2bs0bj.findAll("table")[4].findAll("tr")[2].find("td")
bs0bj.findAll("span", {"class": "green"}).get_text()findAll与find
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15findAll(tag, attributes, recursive, text, limit, keywords)
find(tag, attributes, recursive, text, keywords)
recursive若为True,则不论层数查找;若为False,则查找一级标签
text用文本内容匹配
limit为查找前n个结果
keyword的功能有些冗余,下面两行代码完全一样:
bs0bj.findAll(class_="text")
bs0bj.findAll("", {"class": "text"})
结合正则表达式re:
bs0bj.findAll("img", {"src": re.compile("\.\.\/img\/gifts\/img.*\.jpg")})
结合Lambda表达式:
bs0bj.findAll(lambda tag: len(tag.attrs) == 2)通过导航树
1
2
3
4
5
6
7
8.children(一级标签)
.descendants(所有后代)
.next_sibling(同级之后单个标签)
.next_siblings(同级之后所有标签)
.previous_sibling(同级之前单个标签)
.previous_siblings(同级之后所有标签)
.parent(父标签)
.parents(父标签)递归爬取(示例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19from urllib.request import urlopen
from bs4 import BeautifulSoup
import re
pages = set()
def getLinks(pageUrl):
global pages
html = urlopen("http://en.wikipedia.org"+pageUrl)
bs0bj = BeautifulSoup(html)
for link in bs0bj.findAll("a", href=re.compile("^(/wiki/)")):
if 'href' in link.attrs:
if link.attrs['href'] not in pages:
# 我们遇到了新页面
newPage = link.attrs['href']
print(newPage)
pages.add(newPage)
getLinks(newPage)
getLinks("")存储数据
下载
urllib.urlretrieve(url, path)
将url下载到本地path下
CSV
1 | import csv |
MySQL
通过创建cursor来填充操作数据库的字符串
1
2
3conn = _mysql.connect()
cur = conn.cursor()
cur.execute(SQL)通过query()
1
2db = _mysql.connect()
db.query(SQL)db.query()
是没有游标cursor
时,用来直接执行SQL语句,该类主要逻辑就是,将参数填入SQL语句格式中作为字符串形式的SQL语句,之后用query()
执行语句。读取文档
纯文本
str
: str(text, 'uf8-8')
使用uf8-8编码bytes
: 先用bytes()
将bytes
转化成str
1
2content = bytes(content, "UTF-8")
content = content.decode("UTF-8")
CSV
比较方便的做法是从网上直接把文件读成一个字符串,然后转换成一个StringIO对象,使它具有文件的属性。1
2
3
4
5
6
7
8
9
10from urllib import urlopen
from io import StringIO
import csv
data = urlopen("http://pythonscraping.com/files/MontyPythonAlbums.csv").read().decode('ascii', 'ignore')
dataFile = StringIO(data)
csvReader = csv.reader(dataFile)
# csvReader = csv.DictReader(dataFile)
for row in csvReader:
print(row)
高级数据采集
数据清洗
re.sub(查找字符串, 替换字符串, 文本)
或str.replace(查找字符串, 替换字符串)
(不支持正则)
自然语言处理
n-gram模型
将文本滚动分割出n个单词作为一组,计算所有组的频率,选取出包含该组词汇的句子。马尔可夫模型
后一单词出现的频率只与前一个单词有关,每一个单词构造一个字典,计算所有频次。选取起始词,构造随机数,在该词字典中选中后一单词,以此类推。nltk语言包
穿越网页表单与登录窗口进行采集
使用Requests库进行POST请求
1
2
3
4
5import requests
params = {'firstname': 'Ryan', 'lastname': 'Mitchell'}
r = requests.post("http://pythonscraping.com/files/processing.php", data=params)
print r.text单选按钮、复选框和其他输入一样,只要获取字段和值即可。
上传文件:将open(path)
对象作为字段的值
进行cookie
1
2
3
4
5
6
7
8
9import requests
session = requests.Session()
params = {'username': 'username', 'password': 'password'}
s = session.pos("http://pythonscraping.com/pages/cookies/welcome.php", params)
print(s.cookies.get_dict())
s = session.get("http://pythonscraping.com/pages/cookies/profile.php")
print(s.text)进行接入认证
1
2
3
4
5
6
7import requests
from requests.auth import AuthBase
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth('ryan', 'password')
r = requests.post(url="http://pythonscraping.com/pages/auth/login.php", auth=auth)
print(r.text)采集JavaScript
通过Selenium绑定PhantomJS访问网页,执行JavaScript
图像识别与文字处理
通过Tesseract训练验证码