Spider…

HTTP 状态码测试网址:http://httpstat.us/
作者代码地址:https://bitbucket.org/wswp/
Book’Name:《Web Scraping with Python》
  1. Introduce
  2. Crawl Data
    2.1 RegEx&Beautiful Soup&lxml
  3. Cache Download
    3.1 DiskCache&MongoDB
  4. Multi Process&Threading
  5. Dynamic Content
    5.1 Reverse
    5.2 Dynamic rendering
    5.2.1 PyQt&PySide
    5.2.2 Selenium
  6. Form
    6.1 Aificial&Mechanize
  7. Captcha
  8. Scrapy
    8.1 Portia
  9. Summary

1

urllib2.URLError

可以获取返回的状态码urllib2.URLError.code

用户代理

默认情况下使用Python-urllib/2.7

css选择器-sitemap

使用正则

1
2
3
4
5
def crawl_sitemap(url):
sitemap = download(url)
links = re.findall('<loc>(.*?)</loc>', sitemap)
for link in links:
html = download(link)

itertools

可以用来创建无限迭代器.itertools.count(1)表示自然数序列

urlparse

urlparse.urlparse()

1
2
>>> urlparse.urlparse('https://www.baidu.com')
ParseResult(scheme='https', netloc='www.baidu.com', path='', params='', query='', fragment='')

urlparse.urljoin()

1
2
3
4
5
6
7
8
9
10
>>> urlparse.urljoin('https://www.baidu.com','index.php')
'https://www.baidu.com/index.php'
>>> urlparse.urljoin('https://www.baidu.com/123','index.php')
'https://www.baidu.com/index.php'
>>> urlparse.urljoin('https://www.baidu.com/123','/index.php')
'https://www.baidu.com/index.php'
>>> urlparse.urljoin('https://www.baidu.com/123/','index.php')
'https://www.baidu.com/123/index.php'
>>> urlparse.urljoin('https://www.baidu.com/123/','/index.php')
'https://www.baidu.com/index.php'

注:如果第一个参数有目录的话,记得添加最后的/,并且添加之后不需要第二个参数添加

robotparse

用于判定是否用户代理允许访问页面

1
2
3
4
5
def get_robot(user_agent, url):
rp = robotparser.RobotFileParser()
rp.set_url(urlparse.urljoin(url, '/robots.txt'))
rp.read()
rp.can_fetch(user_agent, url) //返回ture/false

Proxy

使用urllib2支持代理

1
2
3
4
5
request = urllib2.Request(url,...)
opener = urllib2.build_opener()
proxy_params = {urlparse.urlparse(url).scheme: proxy}
opener.add_handler(urllib2.ProxyHandler(proxy_params))
response = opener.open(request)

set

1
2
3
4
5
6
>>> a=set('http://example.webscraping.com/')
>>> print a
set(['a', 'o', 'c', 'b', 'e', 'g', 'n', 'i', 'h', 'm', 'l', '/', '.', 'p', 's', 'r', 't', 'w', 'x', ':'])
>>> a.add('/index/1')
>>> print a
set(['a', 'o', 'c', 'b', 'e', 'g', 'n', 'i', 'h', '/index/1', 'm', 'l', '/', '.', 'p', 's', 'r', 't', 'w', 'x', ':'])

2

Firebug中的html是被js渲染过后的代码,所以与源代码不完全相同

BeautifulSoup

1
2
soup = BeautifulSoup(html) # 把下载下来的html进行格式化
find('li',attrs{'id':'id_value'})、find_all() # 寻找标签,同时可以指定元素

Lxml

1
2
3
4
5
6
7
解析速度要快于BeautifulSoup
XPath和CSS选择器
tree = lxml.html.fromstring(html)
result = tree.cssselect('table > tr#places_area__row > td.w2p_fw')[0].text_content() #cssselect需要下载
a > b : 选择父标签为a的b子标签
a#b : 选择class='b'的a标签
a.b : 选择id='b'的a标签

性能:Lxml/Regex>Beautiful,Lxml是最好的选择

call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Test:
def __init__(self):
print "This is __init__"

def __call__(self, pra):
print "This is __call__{}".format(pra)


def func_test(class_name=None):
for i in range(3):
class_name(1)


if __name__ == '__main__':
func_test(class_name=Test())

Result:

注:call方法在对象作为函数被调用时会调用该方法

抓取方法 性能 难度
RegEx
Beautiful Soup
lxml

3&4

with … as …

with求值的对象必须有一个enter()方法,一个exit()方法
处理顺序:对象被求值后,返回对象的enter方法被调用,返回值被赋值给as后面的变量,with后面的代码块全部执行玩之后,调用对象的返回的exit方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Sample:
def __enter__(self):
print "In__enter__()"
return "Foo"

def __exit__(self, type, value, trace):
print "In__exit__()"


def get_sample():
return Sample()


with get_sample() as sample:
print "sample:", sample

pickle模块

实现了基本的数据序列化和反序列化.序列化之后的对象保存到文件中,从文件中反序列化对象的信息.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pickle.dump(obj,file[,protocol]) //protocol表示序列化模式
pickle.load(file)
Eg2017-06-16 11:25:25 星期五:
import pickle

class pickle_eg:
def __init__(self):
pass


pickle_eg1 = pickle_eg()
f = open('pickle_eg.txt','wb')
pickle.dump(pickle_eg1,f)
f.close()
f = open('pickle_eg.txt','r')
data = pickle.load(f)
f.close()
print data

写入文件和导出的结果:

getitem&setitem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class setandget:
k={}

def __getitem__(self,key):
return self.k[key]

def __setitem__(self,key,value):
self.k[key] = value


a = setandget()
a['test'] = 1
print a['test']

a.__setitem__('test2',2)
print a.__getitem__('test2')
print a['test2']

5

注:Python解析js动态网站:js逆向、渲染js

Json

Ajax响应返回的数据是Json格式的,使用Json模块解析为一个字典

1
2
3
4
5
import json,urllib2
url = 'http://example.webscraping.com/places/ajax/search.json?&search_term=c&page_size=10&page=0'
html = urllib2.urlopen(url).read()
json = json.loads(html)
print json

loads针对对象;load针对文件;

PyQt&PySide

Qt框架下的两个python库,通过Qt框架的库来获得WebKit渲染引擎的python接口

1
2
3
4
5
6
7
8
9
url = 'http://example.webscraping.com/places/default/search'
app = QApplication([])
webview = QWebView()
loop = QEventLoop()
webview.loadFinished.connect(loop.quit)
webview.load(url)
loop.exec_()
webview.show()
html = webview.page().mainFrame()

  1. QApplication对象需要在其他Qt对象完成初始化之前完成创建
  2. QWebView对象是Web文档的容器
  3. QEventLoop对象用于创建本地事件循环
  4. QWebView对象的loadFinished回调连接了QEventLoop的quit方法,从而可以在网页加载完成之后停止事件循环
  5. QWebView加载URL(PyQt需要把URL封装在QUrl对象中)
  6. 由于QWebView加载方法是异步的,因为需要等待网页加载完成,所以调用loop.exec_()
  7. 调用QWebView的show方法来显示渲染窗口
  8. webview.page().mainFrame()返回框架
  9. app.processEvents()用于给Qt事件循环执行任务的时间

Selenium

Chrome缺少驱动需要自行下载再设置为环境变量chromdriver
Firefox 47以上版本下载第三方驱动,geckodriver


6

POST表单

1
2
3
e_data = urllib.urlencode(data)
request = urllib2.Request(url, data)
response = urllib2.urlopen(request)

urlopen使用默认的opener的对象中的open方法
opener可以自定义,通过urllib2.build_opener方法,之后使用opener的open方法打开urllib2.Request

添加cookie

1
2
3
4
5
Cookielib
CookieJar/MozillaCookieJar/FileCookieJar/LWPCookieJar
cookie = Cookielib.CookieJar() //创建放置Cookie的容器
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie)) //自定义opener,使其支持cookie
response = opener.open(urllib2.Request())

build_opener生成一个自定义的opener

获取session文件路径

Windows:
%APPDATA%\Mozilla\Firefox\Profiles\*.default\sessionstore-backups

注:
1.书中说的文件是根目录下的sessionstore.js,如果没有这个文件使用sessionsor-backups下的recovery.js代替即可
2.目录不一定符合这个*.default

Mechanize

可以直接生成表单,并且不需要进行cookie管理

1
2
3
4
5
6
7
import mechanize
me = mechanize.Browser()
me.open(url)
me.select_form(nr=0) // 选择第一个表单
br.form //显示目前表单的状态
br['key'] = value
br.submit() //提交表单


7

Pillow&Tesseract-OCR

pillow的使用需要借助Tessract-OCR

1
2
3
4
5
6
7
8
import pytesseract
from PIL import Image

img = Image.open('captcha.png')
gray = img.convert('L')
bw = gray.point(lambda x: 0 if x < 1 else 255, '1')
tessdata_dir_config = '--tessdata-dir "C:\\Program Files\\Tesseract-OCR\\tessdata"'
print pytesseract.image_to_string(bw, config=tessdata_dir_config)

注:在Win10下安装Tesseravt-OCR之后,tesserdata路径出错,由于驱动器的原因,所以使用的时候需要手动设置tesserdata的路径


(ง •_•)ง