13

爬虫简介

应用场景

搜索引擎;
网站迁移;
数据整理、分析、统计;
跨域、第三方API调用;
还有,嗯钓鱼网站啊;
......

CURL

curl是利用URL语法在命令行方式下工作的开源文件传输工具。它被广泛应用在Unix、多种Linux发行版中,并且有DOS和Win32、Win64下的移植版本
Shell:

curl https://www.segmentfault.com

传统CURL式爬虫过程

  1. 模拟浏览器请求-
    编程语言内置对象或方法模拟设置cookie,User-Agent,Request Method,Query String甚至跟踪redirect,向服务器发送一个请求
  2. 接收、处理数据流-
    对服务器响应数据流字符进行解析,或模拟HTML格式转换为程序相应数据类型方便操作
  3. 保存数据-
    对数据分析后本地持久化存储(CSV,txt,jpg/png,.json文件,DB)

各语言的CURL实现:

PHP:curl_init();
Java:URLConnection;
Python:requests模块;
Node:http模块;
...

CURL式爬虫缺点:

无法获取由Js脚本动态生成的网页信息-
当今Web技术的大环境下,为了网站的性能、可扩展性、用户友好等方向,几乎所有的Web页面都在使用浏览器脚本动态生成内容,所以如果没有脚本执行环境就没有数据。

Headless浏览器实现页面解析

什么是Headless browser?

无头浏览器类似于在流行的Web浏览器的环境中提供对网页的自动控制,但通过命令行接口或使用网络通信来执行。它们特别适用于测试网页,因为它们能够以浏览器相同的方式呈现和解释HTML,包括页面布局、颜色、字体选择和JavaScript和Ajax的执行等样式元素,当使用其它测试方法时,这些元素通常是不可用的
引自Wikipedia Headless browser
简单来说就是用浏览器来对目标URL进行HTML解析,CSS渲染,Js执行,借由API甚至可以模拟用户行为(鼠标点击,键盘输入),但不提供UI渲染。

通过以上我们可以知道Headless browser就是我们想要的爬虫方式了,本文旨在探讨网页爬虫故不对其它用途特性做过多说明。

常用Headless browser

Phantomjs(项目暂封存,慎用);
Chrome
FireFox

环境

Python + Selenium + ChromeDriver

解释

Python

语法简单,有各种成熟扩展库,爬虫周边的库可以轻易找到

Selenium

Selenium-主要是为了自动化测试Web应用程序,但不局限于此-
一句话解释:控制浏览器,做任何想做的事情。(鼠标点击、拖拽;用户输入,表单填充;History and Location API;Cookie;弹出对话框;定位和操作UI元素,执行JavaScript脚本)因此获取通过ajax渲染的页面的数据就不是什么难事了:)
Documentation

ChromeDriver

如上所述,Selenium可以操作浏览器,但是需要借助ChromeDriver它是实现 WebDriver 有线协议的一个开源工具,它提供了导航到网页、用户输入、JavaScript执行等等的能力。ChromeDriver通过chrome的自动代理框架控制浏览器

安装

  1. 安装 Python -
    下载并配置好环境变量,shell输入:python -V 出现对应版本号即安装成功!
  2. 安装pip(Python包管理工具)-
    python默认自带 pip 在安装目录的scripts目录下,自行配置至环境变量即可,配置好后shell输入:pip -V 出现对应版本号即安装成功!
  3. 安装selenium-
    shell输入:pip install selenium 提示:Successfully installed selenium-即安装成功!
  4. 安装ChromeDriver-
    下载ChromeDriver,注意版本需与浏览器版本对应,附:版本号对应描述(64位浏览器下载32位即可),下载后与chrome安装目录放在一起,然后配置至环境变量即可,配置好后shell输入:chromedriver 无错误即安装成功!
  5. 安装python IDE pyCharm

使用

以下将通过两个小例子来了解Selenium :)

百度搜索关键字“Python”

1. 实例化Driver并获取页面

文件名:searchPython.py

from selenium import webdriver # 从selenium导入webdriver

driver = webdriver.Chrome()  # Optional argument, if not specified will search path.
driver.get('https://www.baidu.com') # 获取百度页面

Shell:

py searchPython.py

chromeDriver属性及方法
显示如下:
百度页面

2. 获取输入框元素:

input = driver.find_element_by_id('kw') #获取输入框
searchButton = driver.find_element_by_id('su') #获取搜索按钮

常用查找元素方法:

  1. find_element_by_id # ID
  2. find_elements_by_class_name # class
  3. find_elements_by_tag_name # 标签名
  4. find_elements_by_name # name
  5. find_elements_by_link_text # a标签中的text查找(精确匹配)
  6. find_elements_by_partial_link_text #a标签中的text查找(部分匹配即可)
  7. find_elements_by_css_selector # css选择器查找
  8. find_elements_by_xpath # find_elements_by_xpath("//input"),请翻阅文档

查看常用定位元素方法
注:find_element_by_ 将获取 find_elements_by_ 的第一个元素,获取到的元素会被包装为 WebElement 对象
以上定位元素方法还可以通过如下方式实现:

from selenium.webdriver.common.by import By #支持的定位器策略集
driver.find_element(By.ID,'kw')
driver.find_element(By.ID,'su')
'''注释
策略集如下:
CLASS_NAME = 'class name'
CSS_SELECTOR = 'css selector'
ID = 'id'
LINK_TEXT = 'link text'
NAME = 'name'
PARTIAL_LINK_TEXT = 'partial link text'
TAG_NAME = 'tag name'
XPATH = 'xpath'
'''

3. 输入并点击

inputElement.send_keys("Python") #输入框输入"Python"
searchButton.click() #搜索

WebElement属性及事件API
显示如下:
百度搜索Python

完整代码

from selenium import webdriver # 从selenium导入webdriver

driver = webdriver.Chrome()  # Optional argument, if not specified will search path.
driver.get('https://www.baidu.com') # 获取百度页面
inputElement = driver.find_element_by_id('kw') #获取输入框
searchButton = driver.find_element_by_id('su') #获取搜索按钮

inputElement.send_keys("Python") #输入框输入"Python"
searchButton.click() #搜索

获取 bilibili 网站js动态生成的某栏目标题

这里涉及两个概念:
显式等待(Explicit Waits)-
在给定的条件函数返回True之前,设置一个最长等待时间,和重复执行给定条件函数的间隔时间,如果条件函数在规定时间内返回True则即刻继续执行,否则将抛出一个异常!
隐式等待(Implicit Waits)
告诉WebDriver在试图找到一个元素或元素时,如果它们没有立即可用,则会在一定时间内对DOM进行轮询,默认设置为0,一旦设置,就为WebDevor对象实例的生命周期设置隐式等待。

Explicit Waits

文件名:bilibili.py

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait # 用于实例化一个Driver的显式等待
from selenium.webdriver.common.by import By # 内置定位器策略集
from selenium.webdriver.support import expected_conditions as EC # 内置预期条件函数,具体API请参考此小节后API链接

driver = webdriver.Chrome()
driver.get('https://www.bilibili.com/v/game/esports/?spm_id_from=333.334.primary_menu.35#/9222')
try:
    WebDriverWait(driver, 20, 0.5).until(EC.presence_of_all_elements_located((By.CLASS_NAME,'vd-list'))) #使用expected_conditions自带验证函数
    for doctorName in driver.find_elements_by_css_selector('.vd-list li'):
        print(doctorName.find_element_by_css_selector('.r > a').text)
finally:
    driver.close() # close the driver
WebDriverWait

构造器,接受一个Driver实例,超时时长(秒),执行条件函数的间隔时间。用于实例化一个Driver的显式等待
方法:
1.until(method, message='')

调用第一个参数给定的函数,直到函数不返回False,除了可以接受expected_conditions内置预期条件函数还可以自定义函数,如下

例:

def hasDoctors(d): # 自定义条件函数 when the function is called , the first prms will be a driver
if (len(d.find_elements_by_css_selector('.vd-list li'))):
    return True
return False
WebDriverWait(driver, 20, 0.5).until(hasDoctors) # 自定义函数形式

2.until_not(method, message='')

与until相反
expected_conditions

支持的内置的预期条件,简称EC,如下:
title_is:判断当前页面的title是否完全等于(==)预期字符串
title_contains:判断当前页面的title是否包含预期字符串
presence_of_element_located:判断某个元素是否被加到了dom树里,并不代表该元素一定可见
visibility_of_element_located:判断某个元素是否可见,可见代表元素非隐藏,并且元素的宽和高都不等于0
visibility_of:与上述的方法一样,区别是上述方法要传入元祖locator即(By.ID,'kw'),此方法直接传定位到的WebElement
presence_of_all_elements_located:判断是否至少有1个元素存在于dom树中,有则返回WebElements列表
text_to_be_present_in_element:判断元素的text是否包含预期字符串
text_to_be_present_in_element_value:判断元素的value属性是否包含预期字符串
frame_to_be_available_and_switch_to_it:检查给定帧是否可切换到,如果可以,则将给定的驱动器切换到指定的iframe
......
这里包含了所有的预置条件说明

运行Shell如下:
clipboard.png


shjeff
30 声望3 粉丝

前端工程师


« 上一篇
Web Worker API