Python爬虫基础
一、HTTP协议
1.TCP/IP 四层 与 OSI 七层
image2.HTTP 协议
-
物理层:电器连接
-
数据链路层:交换机,STP,帧中继
-
网络层:路由器,IP 协议
-
传输层:TCP、UDP 协议
-
会话层:建立通信连接,网络拨号
-
表示层:每次连接只处理一个请求
-
应用层:HTTP、FTP
-
应用层的协议
-
无连接:每次连接只处理一个请求
-
无状态:每次连接、传输都是独立的
-
2.HTTP HEADER
REQUEST 部分的 HTTP HEADER
Accept: text/plain
Accept-Charset: utf-8
Accept-Encoding: gzip, deflate
Accept-Language: en-US
Connection: keep-alive
Content-Length: 348
Content-Type: application/x-www-form-urlencoded
Date: Tue, 15 Nov 1994 08:12:31 GMT
Host: en.wikipedia.org:80
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0
Cookie: $Version=1; Skin=new;
3.keep-alive
HTTP是一个请求<->响应模式的典型范例,即客户端向服务器发送一个请求信息,服务器来响应这个信息。在老的HTTP版本中,每个请求都将被创建一个新的客户端->服务器的连接,在这个连接上发送请求,然后 接收请求。这样的模式有一个很大的优点就是,它很简单,很容易理解和 编程实现;它也有一个很大的缺点就是,它效率很低,因此Keep-Alive被提出用来解决效率低的问题。Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。
HTTP/1.1
默认情况下所在HTTP1.1中所有连接都被保持,除非在请求头或响应头中指明要关闭:Connection: Close
- RESPONSE 的 HTTP HEADER
Accept-Patch: text/example;charset=utf-8
Cache-Control: max-age=3600
Content-Encoding: gzip
Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT
Content-Language: da
Content-Length: 348
ETag: "737060cd8c284d8af7ad3082f209582d“
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Location: http://www.w3.org/pub/WWW/People.html
Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1
Status: 200 OK
4.HTTP 响应状态码
2XX 成功
3XX 跳转
4XX 客户端错误
500 服务器错误
- HTTP 响应状态码 300
300 Multiple Choices 存在多个可用的资源,可处理或丢弃
301 Moved Permanetly 重定向
302 Found 重定向
304 Not Modified 请求的资源未更新,丢弃
- HTTP 响应状态码 400、500
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
401 Unauthorized 请求未经授权,这个状态代码必须和WWW-
Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务
404 Not Found 请求资源不存在,eg:输入了错误的URL
500 Internal Server Error 服务器发生不可预期的错误
503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间 后可能恢复正常
5.错误处理
400 Bad Request 检查请求的参数或者路径
401 Unauthorized 如果需要授权的网页,尝试重新登录
403 Forbidden
如果是需要登录的网站,尝试重新登录
IP被封,暂停爬取,并增加爬虫的等待时间,如果拨号网络,尝试重新联网更改IP
404 Not Found 直接丢弃
5XX 服务器错误,直接丢弃,并计数,如果连续不成功,WARNING 并停 止爬取
二、 网页抓取原理
image1.深度优先策略
深度优先策略2.宽度优先策略
宽度优先策略2.XPath
基本语法- @ 属性
在DOM树,以路径的方式查询节点 通过 @ 符号来选取属性
image
rel class href 都是属性,可以通过 "//*[@class='external text']"
来选取对应元素
= 符号要求属性完全匹配,可以用 contains 方法来部分匹配,例如
“//*[contains(@class, ‘external’)]” 可以匹配,而
"//*[@class='external']" 则不能
- 运算符
and 和 or 运算符:
选择 p 或者 span 或者 h1 标签的元素
soup = tree.xpath('//td[@class="editor bbsDetailContainer"]//*[self::p or self::span or self::h1]')
选择 class 为 editor 或者 tag 的元素
soup = tree.xpath('//td[@class="editor" or @class="tag"]')
3.正则表达式
表达式 | 释义 |
---|---|
\ | 转移符,例如 ? |
^ | 字符串起始 |
$ | 字符串结束 |
* | 匹配前面子表达式0次或多册 |
+ | 匹配前面字表达式1次或多次 |
? | 匹配前面子表达式0次或1次 |
{n,m} | 匹配至少n次,最多m次 |
. | 匹配除\n 之外的单个字符 |
(pattern) | 匹配并获取这个匹配,例如匹配ab(cd)e 正则表达式只返回cd |
[xyz] | 字符集合,匹配任意集合里的字符 |
[^xyz] | 排除集合里的字符,不能匹配 |
\d | 匹配一个数字,等价[0-9] |
4.正则规则的常用示例
获取标签下的文本 '<th[^>]>(*.*?)</th>'
查找特定类别的链接,例如/wiki/不包含Category目录:
'<a href="/wiki/(?!Category:)[^/>]>(*.?)<*
查找商品外链,例如jd的商品外链为7位数字的a标签节点
'/\d{7}.hmtl'
查找淘宝的商品信息,' 或者 " 开始及结尾
'href=[\"\']{1}(//detail.taobao.com/item.htm[^>\"\'\s]+?)"'
5.贪婪模式及非贪婪模式
? 该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串
三、动态网页
-
对于爬虫:
- 简单下载HMTL已经不行了,必须得有一个Web容器来运行HTML的脚本
- 增加了爬取的时间
- 增加了计算机的CPU、内存的资源消耗
- 增加了爬取的不确定性
-
对于网站:
- 为了配合搜索引擎的爬取,与搜索相关的信息会采用静态方式
- 与搜索无关的信息,例如商品的价格、评论,仍然会使用动态加载
1.Python Web 引擎
- PyQt PySide:基于QT的python web引擎,需要图形界面的支持,需要 安装大量的以来。安装和配置复杂,尤其是安装图形系统,对于服务器来 说代价很大
- Selenium:一个自动化的Web测试工具,可以支持包括 Firefox、
chrome、PhatomJS、IE 等多种浏览器的连接与测试 - PhantonJs:一个基于Webkit的 Headless 的Web引擎,支持
JavaScript。相比 PyQt 等方案,phamtoms 可以部署在没有UI的服务 器上
2.安装
Selenium
pip install selenium
PhantomJS
PhantomJS 需要先安装 nodejs
# yum install nodejs
为了加速,将NPM的源改为国内的淘宝
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
利用NPM的Package Manager 安装 phantomjs
$ npm -g install phantomjs-prebuilt
3.使用 PhantomJS 来加载动态页面
# import webdriver from selenium
from selenium import webdriver
# load PhantomJS driver
driver = webdriver.PhantomJS(service_args=['--ignore-ssl-errors=true'])
# set window size, better to fit the whole page in order to # avoid dynamically loading data driver.set_window_size(1280, 2400) # optional
# data page content
driver.get(cur_url)
# use page_source to get html content
content = driver.page_source
- set_window_size
对于动态网页,有可能存在大量数据是根据视图来动态加载的,
PhantomJS 允许客户端设置用来模拟渲染页面的窗口的尺寸,这个尺寸如
果设置比较小,我们就不得用 javascript 的 scroll 命令来模拟页面往下滑 动的效果以显示更多内容,所以我们可以设置一个相对大的窗口高度来渲染
driver.set_window_size(1280, 2400) # optional
4.Built-in DOM selector
Selenium 实现了一系列的类似于 xpath 选择器的方法,使得我们可以直接 调用 driver. find_element() 来进行元素的选择,但是这些都是基于Python的实现,执行效率非常低,大约是基于C 的 正则表达式或 lxml 的10倍的时间,因此不建议使用built-in的选择器,而是采用 lxml 或者 re 对driver.page_source (html文本)进行操作
find_element(self, by='id', value=None)
find_element_by_class_name(self, name)
find_element_by_id(self, id_)
find_element_by_css_selector(self, css_selector)
5. 使用发方法和属性解析
Selenium 通过浏览器的驱动,支持大量的HTML及Javascript的操作,常用的可以包括:
page_source: 获取当前的 html 文本
title:HTML 的 title
current_url:当前网页的URL
get_cookie() & get_cookies():获取当前的cookie
delete_cookie() & delete_all_cookies():删除所有的cookie
add_cookie():添加一段cookie
set_page_load_timeout():设置网页超时
execute_script():同步执行一段javascript命令
execute_async_script():异步执行javascript命令
6.Close and Clear
nium 通过内嵌的浏览器 driver 与浏览器进程通信,因此在退出的时候必须调用driver.close() 及 driver.quit() 来退出 PhantomJS,否则 PhantomJS 会一直运行在后台并占用系统资源。
image
7.提取动态数据
# try several times to extract data
while number_tried < constants['MAX_PAGE_TRIED']:
try:
price_element = driver.find_element_by_class_name('J-p-%s' % (item_id))
price = re.findall('\d.*', price_element.get_attribute('innerHTML'))[0] item_name_element = driver.find_element_by_class_name('sku-name')
item_name = item_name_element.text
# item rating has 2 possible bound class, percent-con and rate # try to get rating values with both classes
perc = re.findall('class="percent-con"', driver.page_source)
if len(perc) > 0:
element = driver.find_element_by_class_name('percent-con')
rating = element.text
else:
element = driver.find_element_by_class_name('rate')
rating = element.find_element_by_tag_name('strong').text
break
except selenium.common.exceptions.NoSuchElementException, msgs:
number_tried += 1
print msgs[1]
except Exception, msgs:
print msgs[1]
8.PhantomJS 配置
--ignore-ssl-errors=[true|false] ignores SSL errors, such as expired or self- signed certificate errors (default is false). Also accepted: [yes|no].
--load-images=[true|false] load all inlined images (default is true). Also
accepted: [yes|no].
--disk-cache=[true|false] enables disk cache (at desktop services cache storage location, default is false). Also accepted: [yes|no].
--cookies-file=/path/to/cookies.txt specifies the file name to store the persistent Cookies.
--debug=[true|false] prints additional warning and debug message,
default is false. Also accepted: [yes|no].
--config specifies JSON-formatted configuration file (see below).
9.重要的配置-ignore-ssl-errors
--ignore-ssl-errors=[true|false]
一些证书没有获得CA授权(多是自己制作的证书),浏览器会报出证书不受信任,这
种情况需要用户交互操作(点击继续或者新人),使用这个命令后,能自动忽略此类错
误
- 重要的配置- config
- image