通用爬虫的套路

  • 准备 url
    • 准备 start_url
      • url 地址规律不明显,总数不确定
      • 通过代码提取下一页URL
        • xpath
        • 寻找 url 地址,部分参数在当前响应中(比如,当前页码数和总的页码数在当前的响应中)
    • 准备 url_list
      • 页码总数明确
      • URL地址规律明显
  • 发送请求,获取响应
    • 添加随机的 User-Agent,反反爬虫
    • 添加随机的代理IP,反反爬虫
    • 在对方判断出我们是爬虫之后,应该添加更多的 header字段,包括cookie
    • cookie的处理可以使用session来解决
    • 准备一堆能用的cookie,组成cookie池
      • 如果不登录
        • 准备刚开始能够成功请求对方网站的cookie,即接收对方网站设置在response的cookie
        • 下次请求的时候,使用之前的列表中的cookie来请求
      • 如果登录
        • 准备多个账号
        • 使用程序获取每个账号的cookie
        • 之后请求登录之后才能访问的网站随机的选择cookie
  • 提取数据
    • 确定数据的位置
      • 如果数据在当前页面的url地址中
        • 提取的是列表页的数据
          • 直接请求列表页的URL地址,不用进入详情页
        • 提取详情页的数据
            1. 确定url
            1. 发送请求
            1. 提取数据
            1. 返回
      • 如果数据不在当前URL地址中
        • 在其他响应中,寻找数据的位置
            1. 从 network 中从上往下寻找
            1. 使用chrome中过滤条件,选择除了 js ,css , img 之外的按钮
            1. 使用chrome的search all file,搜索数字和英文
    • 数据提取
      • xpath,从html中提取整块的数据,先分组,之后每一组再提取
      • re,提取max_time,price,html中的json字符串
      • json
  • 保存
    • 保存在本地,text、 json、csv
    • 保存在数据库

xpath的包含

  • //div[contains(@class,"i")]

爬虫代码建议

  • 尽量减少请求次数
      1. 能抓列表就不用抓详情页
      1. 保存获取到的html页面,供查错和重复请求使用
  • 关闭网站的所有类型的页面
      1. wap页面,触屏版页面
      1. H5页面
      1. APP
  • 多伪装
      1. 动态的UA
      1. 代理IP
      1. 不使用cookie
  • 利用多线程分布式
    在不被ban的请求下尽可能提高速度

技巧

自定义UA(User-Agent)代理池

  • 自己构建
# ua_info.py
ua_list = [
    'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
    'User-Agent:Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
    'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
    'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
    'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
    'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0',
    ' Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1',
    'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1',
    ' Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
]
  • 第三方构建

您也可以使用专门第三方的模块来随机获取浏览器 UA 信息,不过该模块需要单独安装,安装方式如下:
pip install fake-useragent

from fake_useragent import UserAgent
#实例化一个对象
ua=UserAgent()
#随机获取一个ie浏览器ua
print(ua.ie)
print(ua.ie)
#随机获取一个火狐浏览器ua
print(ua.firefox)
print(ua.firefox)

爬虫程序结构

# 程序结构
class xxxSpider(object):
    def __init__(self):
        # 定义常用变量,比如url或计数变量等
       
    def get_html(self):
        # 获取响应内容函数,使用随机User-Agent
   
    def parse_html(self):
        # 使用正则表达式来解析页面,提取数据
   
    def write_html(self):
        # 将提取的数据按要求保存,csv、MySQL数据库等
       
    def run(self):
        # 主函数,用来控制整体逻辑
       
if __name__ == '__main__':
    # 程序开始运行时间
    spider = xxxSpider()
    spider.run()

python爬虫忽略ssl证书验证问题

# 1. 导入Python SSL处理模块
import ssl

# 2. 表示忽略未经核实的SSL证书认证
context = ssl._create_unverified_context()
......
# 3. 在urlopen()方法里 指明添加 context 参数
response = urllib2.urlopen(request, context = context)

SSL认证-verify参数

response = requests.get(
url=url,
params=params,
headers=headers,
verify=False
)

代理IP-proxies参数

插件[http://c.biancheng/python_spider/switchyomega.html]
一些网站为了限制爬虫从而设置了很多反爬策略,其中一项就是针对 IP 地址设置的。比如,访问网站超过规定次数导致流量异常,或者某个时间段内频繁地更换浏览器访问,存在上述行为的 IP 极有可能被网站封杀掉。

代理 IP 就是解决上述问题的,它突破了 IP 地址的访问限制,隐藏了本地网络的真实 IP,而使用第三方 IP 代替自己去访问网站。

  1. 代理IP池
    通过构建代理 IP 池可以让你编写的爬虫程序更加稳定,从 IP 池中随机选择一个 IP 去访问网站,而不使用固定的真实 IP。总之将爬虫程序伪装的越像人,它就越不容易被网站封杀。当然代理 IP 也不是完全不能被察觉,通过端口探测技等术识仍然可以辨别。其实爬虫与反爬虫永远相互斗争的,就看谁的技术更加厉害。
  2. proxies参数
    Requests 提供了一个代理 IP 参数proxies,该参数的语法结构如下:
    proxies = {
    ‘协议类型(http/https)’:‘协议类型://IP地址:端口号’
    }
    下面构建了两个协议版本的代理 IP,示例如下:
    proxies = {
    ‘http’:‘http://IP:端口号’,
    ‘https’:‘https://IP:端口号’
    }
  3. 代理IP使用
    下面通过简单演示如何使用proxies参数,示例如下:
import requests
​
url = 'http://httpbin/get'
headers = {
    'User-Agent':'Mozilla/5.0'
}
# 网上找的免费代理ip
proxies = {
    'http':'http://191.231.62.142:8000',
    'https':'https://191.231.62.142:8000'
}
html = requests.get(url,proxies=proxies,headers=headers,timeout=5).text
print(html)
输出结果:
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Cache-Control": "max-age=259200",
    "Host": "httpbin",
    "User-Agent": "Mozilla/5.0",
    "X-Amzn-Trace-Id": "Root=1-605073b0-4f54db1b2d2cfc0c074a1193"
  },

  # 注意此处显示两个IP,第一个是你自己的真实IP,另外一个是对外展示的IP
  "origin": "121.17.25.194, 191.235.72.144", 
  "url": "http://httpbin/get"
}

由于上述示例使用的是免费代理 IP,因此其质量、稳定性较差,可能会随时失效。如果想构建一个稳定的代理 IP 池,就需要花费成本。
4) 付费代理IP
网上有许多提供代理 IP 服务的网 站,比如快代理、代理精灵、齐云代理等。这些网站也提供了相关文档说明,以及 API 接口,爬虫程序通过访问 API 接口,就可以构建自己的代理 IP 池。

  • 付费代理 IP 按照资源类型可划分为:开发代理、私密代理、隧道代理、独享代理,其中最常使用的是开放代理与私密代理。

  • 开放代理:开放代理是从公网收集的代理服务器,具有 IP 数量大,使用成本低的特点,全年超过 80% 的时间都能有 3000 个以上的代理 IP 可供提取使用。

  • 私密代理:私密代理是基于云主机构建的高品质代理服务器,为您提供高速、可信赖的网络代理服务。私密代理每天可用 IP 数量超过 20 万个,可用率在 95 %以上,1 次可提取 IP 数量超过 700 个,可以为爬虫业务提供强大的助力。

付费代理的收费标准根据 IP 使用的时间长短,以及 IP 的质量高低,从几元到几百元不等。89 免费代理(http://www.89ip/)是一个专门提供免费代理 IP 的网站,不过想找到一个质量较高的免费代理好比大海捞针。

用户认证-auth参数

Requests 提供了一个auth参数,该参数的支持用户认证功能,也就是适合那些需要验证用户名、密码的网站。auth 的参数形式是一个元组,其格式如下:
auth = ('username','password')

class xxxSpider(object):
  def __init__(self):
    self.url = 'http://code.tarena/AIDCode/aid1906/13Redis/'
    # 网站使用的用户名,密码
    self.auth = ('name','******')def get_headers(self):
      headers = {'User-Agent':"Mozilla/5.0"}
      return headers
​
  def get_html(self,url):
      res = requests.get(url,headers=self.get_headers(),auth=self.auth)
      html = res.content
      return html
...

爬虫程序随机休眠

  • 每爬取一个页面随机休眠1-2秒钟的时间
    time.sleep(random.randint(1,2))

怎么查看网页是静态页还是伪静态?

怎么查看网页是静态页还是伪静态?
现在很多浏览器都禁止执行:javascript:alert(document.lastModified)
可以在调式模式中执行。以火狐浏览器为例。
打开目标网页,等加载完成。按F12键调出控制台,在底部就可以输入:javascript:alert(document.lastModified)然后回车。第一次执行为提示有风险,然后要你输入它提示的英文。按提示输入完。再执行上面的代码就可以了。
伪静态时间不一致。
静态时间一致。

多线程爬虫

网络爬虫是一种IO密集型程序,程序中涉及了很多网络IO操作,这些都会消耗大量的时间,
从而降低程序的执行效率,而 python 提供多线程能够在一定程度上提升 IO 密集型程序的执行效率。

Python 提供了两个支持多线程的模块,分别是 _thread 和 threading。其中 _thread 模块偏底层,它相比于 threading 模块功能有限,因此推荐大家使用 threading 模块。 threading 中不仅包含了 _thread 模块中的所有方法,还提供了一些其他方法,如下所示:
threading.currentThread() 返回当前的线程变量。
threading.enumerate() 返回一个所有正在运行的线程的列表。
threading.activeCount() 返回正在运行的线程数量。

### 线程的具体使用方法
from threading import Thread
#线程的创建、启动、回收
t=Thread(target=函数名) # 创建线程对象
t.start() # 创建并启动线程
t.join() # 阻塞等待回收线程

### 创建多线程的具体流程
t_list=[]
for i in range(5):
  t=Thread(target=函数名)
  t_list.append(t)
  t.start()

for t in t_list:
  t.join()

### 在处理线程的过程中要时刻注意线程的同步问题,
    即多个线程不能操作同一个数据,否则会造成数据的不确定性。
    通过 threading 模块的 Lock 对象能够保证数据的正确性。

比如,使用多线程将抓取数据写入磁盘文件,此时,就要对执行写入操作的线程加锁,这样才能够避免写入的数据被覆盖。当线程执行完写操作后会主动释放锁,继续让其他线程去获取锁,周而复始,直到所有写操作执行完毕。具体方法如下所示:
from threading import Lock
lock=Lock()
#获取锁
lock.acquire()
wirter.writerrows("线程锁问题解决")
#释放锁
lock.release() 

Queue队列模型

对于 Python 多线程而言,由于 GIL 全局解释器锁的存在,同一时刻只允许一个线程占据解释器执行程序,当此线程遇到 IO 操作时就会主动让出解释器,让其他处于等待状态的线程去获取解释器来执行程序,而该线程则回到等待状态,这主要是通过线程的调度机制实现的。

由于上述原因,我们需要构建一个多线程共享数据的模型,让所有线程都到该模型中获取数据。queue(队列,先进先出) 模块提供了创建共享数据的队列模型。比如,把所有待爬取的 URL 地址放入队列中,每个线程都到这个队列中去提取 URL。queue 模块的具体使用方法如下:

# 导入模块
from queue import Queue
q = Queue() #创界队列对象
q.put(url) 向队列中添加爬取一个url链接
q.get() # 获取一个url,当队列为空时,阻塞
q.empty() # 判断队列是否为空,True/False

Python BS4解析库用法详解

Beautiful Soup 简称 BS4(其中 4 表示版本号)是一个 Python 第三方库,

pip install bs4
pip install lxml
pip install html5lib

#导入解析包
from bs4 import BeautifulSoup
#创建beautifulsoup解析对象
soup = BeautifulSoup(html_doc, 'html.parser')

## 如果是外部文档,您也可以通过 open() 的方式打开读取,语法格式如下:
soup = BeautifulSoup(open('html_doc.html', encoding='utf8'), 'lxml')

更多推荐

python爬虫 --- 扩展知识