网络爬虫技术(python)

爬虫也用了这么久,最开始用Jave再换到了python。在学习和应用的过程中也遇到了有很多问题,在这里就简要地谈谈 整个过程中关于爬虫技术的一点点个人经验和理解。对于初学者来说,可以将本篇文章作为参考,也欢迎大家分享自己的经验。

本篇文章,主要会依据以下三个步骤来讲解:

  • 一、入门
  • 二、实例
  • 三、进阶

一、入门

1.爬虫基础


1.1).什么是爬虫

爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。爬虫的工作流程较为复杂,需要根据一定的网页分析算法过滤与主题无关的链接,保留有用的链接并将其放入等待抓取的URL队列。然后,它将根据一定的搜索策略从队列中选择下一步要抓取的网页URL,并重复上述过程,直到达到系统的某一条件时停止。另外,所有被爬虫抓取的网页将会被系统存贮,进行一定的分析、过滤,并建立索引,以便之后的查询和检索。


1.2).最佳优先搜索和广度优先搜索

什么叫广度优先
一般来说,广度优先有利于多爬虫的合作抓取(多线程)。最佳优先搜索策略按照一定的网页分析算法,预测候选URL与目标网页的相似度,或与主题的相关性,并选取评价最好的一个或几个URL进行抓取。它只访问经过网页分析算法预测为“有用”的网页。当然,我们可以简单理解为最佳优先搜索是对广度优先搜索的一种改进。对于我们大多数的非搜索引擎爬虫来说,最佳优先搜索再是最适合我们的。


1.3).HTTP协议

HTTP 协议是互联网的基础协议,是网页开发的必备知识,也是网络爬虫需要的基本知识。
HTTP协议通常承载于TCP协议之上,我们有时候可以简单理解为它封装(实现)了tcp/ip协议。有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。在HTTPS连接的时候,我们对网页信息的抓包就会出现困难,需要我们提供响应的证书。当然,这个方面更多是跟安全相关。
这里写图片描述
举例来说,在我们浏览网页的过程,就是建立整个HTTP请求和响应的过程。
总的来说,整个爬虫的过程,就是去模拟(实现)HTTP请求的过程。
简单来说,我们通过HTTP的Get或者post请求,去获取web服务的内容(响应)。
更多关于HTTP的讲解,大家可以查阅相关书籍,如:
《HTTP权威指南》
《图解HTTP》PS: 这本书比较简单
《计算机网络》——作者: 谢希仁 ,出版社: 电子工业出版社


1.4).公理和原则
  • 公理:所有网站均可爬,即:只要是我们能够访问到的网页,我们都可以有办法去抓取(获得)到它的内容。
  • 原则: 以不妨碍目标网站的服务器性能为前提,也叫做’平衡礼貌策略‘。

2.python基础


下面所说的很多语言特性实则是大多数编程语言均具有的功能,这里以Python为实例进行简要的说明。

2.1).基本数据结构
python内置的丰富的数据结构给我们使用。
Python中常见的数据结构可以统称为容器(container)。序列(如列表和元组)、映射(如字典)以及集合(set)是三类主要的容器。
在我们爬虫对数据进行清洗和整理的过程中,选择合适的数据结构来存储和使用,对爬虫的效率和性能会有极大的提升。
a = [] # list
a = {} # dict
a = () #tuple
a = set() #set
...

顺便一提一个python你不得不用并且非常优雅的 ‘列表推导式’

a = [1, 2, 3]
print [_ for _ in a]

2.2).正则表达式

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。

爬虫程序爬取我们需要的东西,那么就要对爬取的结果进行筛选,正则表达式就起到这样的作用,对于爬虫程序来说,正则是我们最最基本也是最必须的工具。

重点:正则表达式的贪婪模式与非贪婪模式

"""
当重复一个正则表达式时,如用 a*,操作结果是尽可能多地匹配模式。当你试着匹配一对对称的定界符,如 HTML 标志中的尖括号。匹配单个 HTML 标志的模式不能正常工作,因为 .* 的本质是“贪婪”的
"""
s = '<html><head><title>Title</title>'
print len(s) # 32
print re.match('<.*>', s).span() #(0,32)
"""
如果想要只匹配出<html>。在这种情况下,解决方案是使用不贪婪的限定符 *?、+?、?? 或 {m,n}?,尽可能匹配小的文本。
代码略
"""

在不同的爬虫需求中,我们需要自己根据业务需求去判断 选择哪种模式去筛选我们需要的结果。


2.3).requests库

Requests: HTTP for Humans

让HTTP服务人类。
Requests 允许你发送纯天然,植物饲养的 HTTP/1.1 请求,无需手工劳动。你不需要手动为 URL 添加查询字串,也不需要对 POST 数据进行表单编码。Keep-alive 和 HTTP 连接池的功能是 100% 自动化的,一切动力都来自于根植在 Requests 内部的 urllib3。
简单点说,我们可以用requests库实现我们所有的http请求(爬虫请求)。

                result = requests.get(re.compile("\s").sub("", url), headers=headers, timeout=10)  # 只需一行
即可抓取网页

2.4).多线程
> 是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个执行绪,进而提升整体处理性能。

爬虫是一个典型的多任务处理场景,在我们大多数爬虫程序中,往往最多是时间是在等待网络io,更详细点说,时间花费在每次HTTP请求时的tcp/ip握手和数据传输上。多线程或进程可以让我们并行地去做这些事情,对于爬虫的效率会有极大的提升。ps:友情提示:请准守 ‘平衡礼貌策略’。


二、实例

以下内容均为伪代码

1).秒秒钟爬取一个网页
page = requests("http://www.baidu.com")

这里写图片描述

当然,requests有很多参数可以使用,具体可以查看requests的官方文档


2).HTTP GET和POST请求
requests.get(url, data=payload) # get请求

""" POST请求 """

payload = {'key1': 'value1', 'key2': 'value2'}
requests.post(url, data=payload)

3).发送HTTP Header信息
rdm = random.uniform(1, 9999999)
headers = {'User-Agent': agent.format(rdm=rdm)}
result = requests.get(url, headers=headers, timeout=10)

4).超时处理

我们可以告诉 requests 在经过以 timeout 参数设定的秒数时间之后停止等待响应,以便防止爬虫卡死或特殊情况导致程序异常结束。

requests.get(re.compile("\s").sub("", url), timeout=10) 

三、进阶


1).爬虫与反爬

整个爬虫抓取的过程。也是我们与服务器斗智斗勇的过程,有的服务器并不希望我们去抓取他的内容和数据,会对我们的爬虫进行限制。
当然,我们始终要记住我们的公理:所有网站均可爬
这里举几个常见的防爬和反爬实例:

1 cookie[session]验证。

这里也涉及到我们上文提到的http协议相关知识,因此希望大家可以多多了解http协议相关知识。
防爬策略:每次请求需要验证码,
反爬策略:其实所谓的验证码,也就是存储在浏览器端的cookie或者服务器端的session[关于cookie和session我们这里不多加讨论,大家可自行去了解。]。我们每次请求时,把cookie通过http header或者post请求一起发送过去即可。

url1, url2 = "验证地址", "实际地址";

""" 获取cookie"""
 def get_cookie(self, r):
        return {cookie.name: cookie.value for cookie in r.cookies}

r = requests.get(url1) # 发送请求
coo = r.cookies['example_cookie_name'] # 得到cookie
cookies =  get_cookie(coo) # 获取cookie

""" 使用cookie """
r = requests.get(url2, cookies=cookies)


2 ip屏蔽

防爬策略:对于一定时间内请求频繁的客户端ip地址,拒绝请求。
反爬策略:更换代理ip。
"""
    如果需要使用代理,我们可以通过为任意请求方法提供 proxies 参数来配置单个请求:
"""
proxies = {
  "http": "http://10.10.1.10:3128",
  "https": "http://10.10.1.10:1080",
}

requests.get("http://example.org", proxies=proxies)

这样对方服务器就不能屏蔽我们了!


3 真人判断

防爬策略:服务器会根据http header头部 user-agent等信息去判断是否是机器还是真实用户,如果不是真实用户,则拒绝请求。
反爬策略:伪造http header头部信息。

""" 此处的关键就是对 user-agent的判断"""
rdm = random.uniform(1, 9999999)
headers = headers or {'User-Agent': agent.format(rdm=rdm)}
result = requests.get(url, headers=headers, timeout=10)

4 网页渲染方式
服务端渲染——举例:典型的php程序,服务端将html文件直接返回浏览器。
客户端渲染——举例: 典型的 http REST API模式,服务端只返回josn数据,客户端渲染结构。
爬虫需要根据不同的网页渲染方式,去采取不同的方式去抓取。一般来说,前者抓取网页内容,后者直接抓取数据接口。


2).多线程模块

为了利用多核,Python开始支持多线程。而解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。 于是有了GIL这把超级大锁,而当越来越多的代码库开发者接受了这种设定后,他们开始大量依赖这种特性(即默认python内部对象是thread-safe的,无需在实现时考虑额外的内存锁和同步操作)。

说下我个人的看法,其实Python内置的多线程模块是非常鸡肋的,是蛋疼且低效的。关于python gil锁可以再写几十页,这里不多说,可自行查阅相关文档说明。个人建议:除非有良好的设计,不推荐为了使用使用python的多线程而使用多线程

"""
简单工厂模式 多线程的调用
"""
class Start(threading.Thread):

    def __init__(self, func, now, names):
        threading.Thread.__init__(self)
        self.func = func
        self.now = now
        self.names = names

    def run(self):
        self.func(self.now, self.names)

3).scrapy框架

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试

建议先写原生的爬虫,再用此框架。


4).异常处理

在爬虫分析过程中,最典型的两个错误就是500+和400+的错误。
对于大多数500的错误情况,往往是服务器拒绝或者阻止了我们的访问请求。这里需要我们针对这些异常情况作出相应的处理。

""" 一个典型的场景,在我们遇到400+或者500+错误的时候,作重抓处理,并且记录log"""
    while(cycle_times):
        try:
            rdm = random.uniform(1, 9999999)
            headers = headers or {'User-Agent': agent.format(rdm=rdm)}
            result = requests.get(re.compile("\s").sub("", url), headers=headers, timeout=10) 
            else:
                result = requests.get(re.compile("\s").sub("", url), headers=headers, timeout=10)
            if result.status_code == 200:
                return result.text
            if result.status_code == 500:
                # print "500错误"
                time.sleep(interval)
                utils.log(message="网络出现错误,{}秒之后会重新抓取\r\n".format(interval))  # noqa
        except:
            time.sleep(interval)
            result = None
        cycle_times -= 1
5).抓包工具

了解HTTP详细的请求过程和数据,有利于我们对爬虫进行更好的分析以及作出更好编码决策。
这里推荐charles——http抓包工具。

6).文本分析

重点:词语文本库
大数据相关:可用spark(类似于java map reduce)进行分析。利用分布式系统极大加快分析速度。


写在最后面的话

上面有的是维基百科外链,需要科学上网才能使用。
校园网是直接可以使用ipv6翻墙的。当然,如果需要的人多,正好我也有个国外的服务器,可以搭建VPN给大家使用。
同时,建议大家养成使用google搜索的习惯,国内的搜索引擎搜索出来的结果准确性差了很多,

看的再多,也需要自己亲自去动手。
Just code it!
开始正式进入爬虫之旅吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值