Python 爬虫坏境搭建与基础知识

662 阅读14分钟

本文主要介绍 Python 3 网络爬虫所需要的软件的安装及配置,以及开始学习爬虫时需要了解的基础知识。

开发环境配置

开发环境

本文以在 macOS X 上使用 Python 3.7 为例,配置一个基础的爬虫开发学习环境。

请求库 安装

网络爬虫,首先要获取网络上的数据,即抓取页面,这就需要我们模拟浏览器向服务器发出请求。 我们可以安装一些 Python 库来帮助我们比较容易地完成这个操作。

让我们来安装它们吧:

  • requests : 网络请求:

    • pip3 inastal requests
  • Selenium : 自动测试工具(驱动浏览器执行特定的动作,如点击、下拉等 操作 ):

    • pip3 install selenium
  • ChromeDriver : 用 Chrome 与 Selenium 配合工作:

    • 安装 Chrome 浏览器
    • 在 Chrome 菜单(“···”) -> “关于 Google Chrome”,查看当前Chrome版本。
    • ChromeDriver官网 下载配对 Chrome 版本的 ChromeDriver(⚠️【注意】ChromeDriver 一定要与 Chrome 的版本兼容!)。
    • 解压下载的文件,得到可执行文件,将其加入环境变量(可以简单地把它放到环境变量中有的目录下)。
  • GeckoDriver: 用 Firefox 与 Selenium 配合工作:

    • 暂时并没有使用 Firefox,所以没有安装这个😂。
  • ~~PhantomJS: 还是配合 Selenium 工作的:

    • (PhantomJS 简介)PhantomJS是一个无界面的、可脚本编程的 WebKit浏览器引擎,它原生支持多种 Web标准: DOM操作、 css选择器、 JSON、 Canvas以及 SVG。Selenium支持 PhantomJS,这样在运行的时候就不会再弹出 一个浏览器了 。 而且 PhantomJS 的运行效率也很高,还支持各种参数配置,使用非常方便。
    • PhantomJS官网 下载 PhantomJS。
    • 将下载得到的目录中的 可执行文件 加入环境变量。
    • ⚠️【注意】在 2018年3月4日, PhantomJS 宣布暂停开发了!Selenium 也不再赞同使用 PhantomJS了。~~
  • aiohttp: 一个异步的 Web 服务库(相比之下 requests 是阻塞式的):

    • pip3 install aiohttp
  • cchardet: 字符编码检测库(aiohttp官方推荐安装的):

    • pip3 install cchardet
  • aiodns: 加速 DNS 的解析库(aiohttp官方推荐安装的):

    • pip3 install aiodns

解析库 安装

抓取网页之后,我们就要从中提取有用的信息了。 我们当然可以使用令人望而生畏的 正则表达式 来完成这一操作; 不过,有很多强大的库可以帮助我们更优雅地处理这一问题。

下面,我们将安装这些库:

  • lxml: 一个 Python 的 HTML、XML 解析库,支持XPath:

    • pip3 install lxml
    • 这个库安装常有问题,主要可能是缺少必要的库,不同的平台,解决办法差异太大,应自行Google。
  • Beautiful Soup: 一个 Python 的 HTML、XML 解析库,拥有强大的API和多种解析方式:

    • pip3 install beautifulsoup4
    • ⚠️【注意】Beautiful Soup 安装好之后的库名是bs4,所以 import 的时候是import bs4
  • pyquery: 一个提供了类似于 jQuery 的语法的 HTML 解析工具,支持 CSS 选择器:

    • pip3 install pyquery
  • tesserocr: 一个 OCR 库,用来处理验证码:

    • tesserocr 是对 tesseract 的 Python API 封装,故要先安装 tesseract
      • $ brew install imagemagick
      • $ brew install tesseract
    • pip3 install tesserocr pillow
    • ⚠️ 这时,在 Mac 上试图 >>> import tesserocr 会遇到 !strcmp(locale, "C"):Error:Assert failed:in file baseapi.cpp 的断言失败,导致 Illegal instruction: 4 使 Python 错误退出。
    • 要解决上述问题,可以通过 $ export LC_ALL=C(临时性),或把 export LC_ALL=C 写入 ~/.bashrc(永久性)。

数据库 安装

  • MySQL: 关系型数据库:

    • $ brew install mysql
  • MongoDB: 非关系型数据库:

    • $ brew install mongodb
  • Redis: 一个基于内存的高效非关系型数据库:

    • $ brew install redis

储存库 安装

储存库 是让 Python 使用我们之前安装好的数据库的库。

  • PyMySQL: 让 Python 与 MySQL 交互:

    • pip3 install pymysql
  • PyMongo: 让 Python 与 MongoDB 交互:

    • pip3 install pymongo
  • redis-py: 让 Python 与 Redis 交互:

    • pip3 install redis
  • RedisDump: 一个用于 Redis 数据导入/导出的工具,基于Ruby:

    • 安装 RedisDump 首先要安装 Ruby,这里我们使用 MacOS 自带的 Ruby。
    • 使用 Ruby 的 gem(类似于pip)安装 RedisDump:
      • $ sudo gem install redis-dump
      • ⚠️【注意】由于安装目录是 MacOS 的一部分,必须要sudo,否则无权安装!

Web库 安装

我们需要用到 Web服务程序 来搭建一些 API接口,供爬虫使用。

  • Flask: 一个轻量级 Web 服务程序,这里用来做一些 API 服务:

    • pip3 install flask
  • Tornado: 一个异步的 Web 框架:

    • pip3 install tornado

App爬取相关库 安装

爬虫框架 安装

  • pyspider:

    • 首先要解决一个依赖问题$ PYCURL_SSL_LIBRARY=openssl LDFLAGS="-L/usr/local/opt/openssl/lib" CPPFLAGS="-I/usr/local/opt/openssl/include" pip3 install --no-cache-dir pycurl
    • $ pip3 install pyspider
    • pyspider v0.3.10 中使用了一个名为 async 的变量,这个名字在 Python 3.7 中被列为了保留字,这意味着二者合作将无法运行!
    • 在这里,我们为了解决这个问题,简单地把 pyspider 模块中所有的 async 替换成了 async_😂。
  • Scrapy:

    • 大多数的安装教程都要先: $ xcode-select --install,但我们跳过了这一步,并没有遇到问题。
    • pip3 install Scrapy
  • Scrapy-Splash: 一个 Scripy 中支持 JavaScript 渲染的工具:

    • 这是一个安装的链条:Scrapy-Splash <- Splash <- Docker
    • 安装 Docker$ brew cask install docker
    • 登录 Docker$ docker login
    • 安装 Splash$ docker run -p 8050:8050 scrapinghub/splash
    • 安装 Scrapy-Splashpip3 install scrapy-splash
  • Scrapy-Redis: Scrapy 的分布式拓展模块:

    • pip3 install scrapy_redis

部署相关库的安装

  • 安装 & 配置 Docker

  • 安装 Scrapyd

    • pip3 install scrapyd
    • $ sudo mkdir /etc/scrapyd
    • $ sudo vim /etc/scrapyd/scrapyd.conf,当然,也可以使用其他任何文本编辑器打开。
    • 在其中写入以下内容(主要是参考官方文档,但做了有限的改动。):
[scrapyd]
eggs_dir    = eggs
logs_dir    = logs
items_dir   =
jobs_to_keep = 5
dbs_dir     = dbs
max_proc    = 0
max_proc_per_cpu = 4
finished_to_keep = 100
poll_interval = 5.0
bind_address = 0.0.0.0
http_port   = 6800
debug       = off
runner      = scrapyd.runner
application = scrapyd.app.application
launcher    = scrapyd.launcher.Launcher
webroot     = scrapyd.website.Root

[services]
schedule.json     = scrapyd.webservice.Schedule
cancel.json       = scrapyd.webservice.Cancel
addversion.json   = scrapyd.webservice.AddVersion
listprojects.json = scrapyd.webservice.ListProjects
listversions.json = scrapyd.webservice.ListVersions
listspiders.json  = scrapyd.webservice.ListSpiders
delproject.json   = scrapyd.webservice.DeleteProject
delversion.json   = scrapyd.webservice.DeleteVersion
listjobs.json     = scrapyd.webservice.ListJobs
daemonstatus.json = scrapyd.webservice.DaemonStatus
  • Scrapyrt:

    • pip3 install scrapyrt
  • Gerapy:

    • pip3 install gerapy

爬虫基础

下面介绍爬虫涉及到的基础知识。

HTTP 基本原理

URI & URL

简写全名中文说明
URIUniform Resource Identifier统一资源标志符对应着一个资源
URLUniform Resource Locator统一资源定位符说明从哪里可以找到一个资源
URNUniversal Resource Name统一资源名称说明一个资源的唯一名字

URI 包含着 URL 和 URN。

通常,我们使用的网址,就是一个URI,同时也是一个URL。

超文本

超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本。

我们平时看到的网页的源代码使用 HTML 写出的,HTML 就是一种超文本。

HTTP & HTTPS

我们用URL访问资源需要指定使用的协议类型,协议就是URL地址一开始的那个字段。

协议全称说明
HTTPHyper Text Transfer Protocol(超文本传输协议)用于从网络传输超文本数据到本地浏览器的传送协议,它能保证高效而准确地传送超文本文档
HTTPSHyper Text Transfer Protocol over Secure Socket Layer(在SSL上的HTTP)以安全为目标的 HTTP 通道,是 HTTP 的安全版

HTTPS 相较于 HTTP 有以下优点:

  • 建立一个信息安全通道来保证数据传输的安全。
  • 确认网站的真实性,凡是使用了 HTTPS 的网站,都可以通过点击浏览器地址栏的锁头标志来 查看网站认证之后的真实信息,也可以通过 CA 机构颁发的安全签章来查询。

HTTP 请求过程

我们在浏览器中输入网址,便显示出一个网页的过程实际上是:

  1. 浏览器向网站的服务器发送了一个请求;
  2. 服务器接收到这个请求后进行解析和处理;
  3. 服务器返回对应的响应;
  4. 浏览器对收到的响应解析;
  5. 浏览器将解析的结果显示出来,即最后我们看到的网页。

我们可以在 Chrome浏览器 的开发者工具的“Network”页面看到的一个条目就是一次 发送请求和接收响应 的过程。

Network的列说明
Name请求的名称,一般会将 URL 的最后一部分内容当作名称 。
Status响应的状态码,这里显示为 200, 代表响应是正常的 。 通过状态码,我们可以判断发送了请求之后是杏得到了正常的响应 。
Type请求的文梢类型 。 这里为 document,代表我们这次请求的是一个 HTML文档, 内容就是一些 HTML代码。
Initiator请求源 。 用来标记请求是由哪个对象或进程发起的 。
Size从服务器下载的文件和请求的资源大小 。 如果是从缓存中取得的资源,则该列会显示from cache。
Time发起请求到获取响应所用的总时间 。
Waterfall网络请求的可视化瀑布流 。

点击条目,我们将看到更加详细的请求、响应信息。

请求(Request)

请求,是由 客户端服务端 发出的。

请求分为4部分:

  • 请求方法(Request Method):常见的请求方法分为两种 GET 和 POST:

    • GET 请求中的参数包含在 URL 里面,数据可以在 URL 中看到(可能暴露敏感信息)。GET请求提交的数据最多只有 1024 字节。
    • POST 请求中的 URL 不包含数据,数据都是通过表单形式传输的,会包含在请求体中。POST方式没有大小限制(可以传文件)。
    • 我们输入一个网址,这是一个 GET 请求。
    • 其实还有一些其他的请求方法,可以参考 HTTP请求方法
  • 请求地址(Request URL):统一资惊定位符 URL,唯一确定我们想请求的资源。

  • 请求头(Request Headers):用来说明服务器要使用的附加信息,比较重要的信息有 Cookie、 Referer、 User-Agent:

    • Accept: 请求报头域,用于指定客户端可 接受哪些类型的信息
    • Accept-Language: 指定客户端可接受的 语言类型
    • Acceot-Encoding: 指定客户端可接受的 内容编码
    • Host: 指定 请求资源的主机 IP 和端口号,其内容为 请求 URL 的原始服务器或网关的位置
    • Cookies: 网站为了辨别用户进行会话跟踪而 存储在用户本地的数据。它的主要功能是 维持当前访问会话,如检查用户登录。
    • Referer: 此内容用来标识这个请求是从哪个页面发过来的,服务器可以拿到这一信息并做相 应的处理,如做来源统计、防盗链处理等 。
    • User-Agent: 简称 UA,它可以使服务器识别客户使用的操作系统及版本、浏览器及版本等信息。 在做爬虫时加上此信息,可以伪装为浏览器; 如果不加,很可能会被识别州为爬虫 。
    • Content-Type: 也叫互联网媒体类型( Internet Media Type )或者 MIME类型,在 HTTP协议消息头中,它用来表示具体请求中的媒体类型信息。请求头是请求的重要组成部分,在写爬虫时,大部分情况下都需要设定请求头。
  • 请求体(Request Body):

    • POST 的请求体是表单数据;
    • GET 的请求体为空;

响应(Response)

响应,由 服务端 返回给 客户端

  • 响应状态码(Response Status Code):表示服务器的响应状态
    • HTTP状态码分类,具体HTTP状态码列表,见HTTP状态码
分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误
  • 响应头(Response Headers): 响应头包含了服务器对请求的应答信息

    • Date: 标识 响应产生的时间
    • Last-Modified: 指定 资源的最后修改时间
    • Content-Encoding: 指定响应 内容的编码
    • Server: 包含 服务器的信息,比如名称、版本号等
    • Content-Type: 文档类型,指定 返回的数据类型 是什么(和 Request 的一样)
    • Set-Cookie: 设置 Cookies。告诉浏览器需要将此内容放在 Cookies 中, 下次请求携带 Cookies 请求
    • Expires: 指定响应的过期时间,可以使代理服务器或浏览器将加载的内容更新到缓存中。如果再次访问时,就可以直接从缓存中加载,降低服务器负载,缩短加载时间。
  • 响应体(Response Body)响应的正文数据都在响应体中

    • 请求网页时,它的响应体就 是网页的 HTML代码
    • 请求一张图片时, 它的响应体就是图片的二进制数据
    • 我们做爬虫请求网页后,要解析的内容就是响应体

网页基础

网页分为三大部分 ———— HTML(框架),CSS(样式),JavaScript(逻辑)。

HTML, 超文本标记语言

详见 HTML 教程

Another recommended HTML guide: www.websiteplanet.com/blog/html-g…

CSS, 层叠样式表

详见 CSS 教程

JavaScript, 脚本语言

详见 JavaScript 教程

网页结构

在 HTML 中,所有标签定义的内容都是节点,它们构成了一个 HTML DOM 树。(DOM:文档对象模型) 通过 HTML DOM,树中的所有节点均可通过 JavaScript访问,所有 HTML 节点元素均可被修改,也可以被创建或删除 。

详见 HTML DOM 教程

选择器

在 css 中,我们使用 css 选择器来定位节点。

详见 CSS 选择器表

爬虫的基本原理

爬虫是获取网页并提取保存信息的自动化程序

可以说,我们能在浏览器中看到的一切内容,都可以通过爬虫得到(包括那些由JavaScript渲染出来的网页)。

爬虫主要解决以下几个问题:

获取网页

构造一个请求并发送给服务器,然后接收到响应并将其解析出来。

我们可以用urllib、 requests 等库来帮助我们实现 HTTP请求操作,请求和响应都可以用类库提供的数据结构来表示,得到响应之后只需要解析数据结构中的 Body 部分即可,即得到网页的源代码。

提取信息

分析网页源代码,从中提取我们想要的数据。

最通用的方法是采用 正则表达式 提取,这是一个万能的方法,但是在构造正则表达式时比较复杂且容易出错。 使用 Beautiful Soup、 pyquery、 lxml 等库,我们可以高效快速地从中提 取网页信息,如节点的属性、文本值等。

保存数据

将提取到的数据保存到某处以便后续使用。

自动化程序

让爬虫来代替人,完成上述这些操作。 并在抓取过程中进行各种异常处理、错误重试等操作,确保爬取持续高效地运行。

会话 和 Cookies

HTTP 本身是无状态的,这是指 HTTP 协议对事物的处理是没有记忆能力的。 换言之,服务器 不知道 客户端是说明状态。

然而,我们日常接触的很多网页都可以实现用户登录等需要服务器记住客户端的操作。 实现这一类操作,就会用到 会话Cookies

会话

会话,是一系列有始有终的动作/消息。例如,从拿起电话拨号到挂断 电话这中间的一系列过程可以称为一个会话。

在 Web 中,会话对象 用来存储特定用户会话所需的属性及配置信息。

当用户在应用程序的 Web 页之间跳转时,存储在会话对象中的变量将不会丢失(如用户的登录状态); 当用户请求来自应用程序的 Web 页时如果该用户还没有会话,则服务器将自动创建一个会话对象 ; 当会话过期或被放弃后,服务器将终止该会话;

Cookies

Cookies指某些网站为了辨别用户身份、进行会话跟踪而存储在用户本地终端上的数据。

服务器可以通过 Cookies 得知 那个客户端对应着那个会话、那个用户。 在 客户端Cookies服务端会话 的协作下,我们便可以实现会话的维持。

Cookie有如下几个属性 :

  • Name: 该 Cookie 的名称。一旦创建,该名称便不可更改。

  • Value: 该 Cookie 的值。

    • 如果值为 Unicode 字符,需要为字符编码。
    • 如果值为二进制数据,则需要使用 BASE64 编码。
  • Domain: 可以访问该 Cookie的域名。例如,如果设置为 .zhihu.com,则所有以 zhihu.com 结尾的域名都可以访问该 Cookie。

  • MaxAge: 该 Cookie失效的时间,单位为秒,也常和 Expires 一起使用,通过它可以计算有效时间。

    • MaxAge 如果为正数,则该Cookie在MaxAge秒之后失效。
    • 如果为负数,则关闭 浏览器时 Cookie 即失效,浏览器也不会以任何形式保存该 Cookie。
  • Path : 该 Cookie 的使用路径。 如果设置为 /path/,则只有路径为 /path/ 的页面可以访问该 Cookie。 如果设置为 / 则本域名下的所有页面都可以访问该 Cookie。

  • Size字段: 此 Cookie 的大小。

  • HTTP 字段: Cookie 的 httponly 属性。

    • 若此属性为 true,则只有在 HTTP 头中会带有此 Cookie的信息,而不能通过 document.cookie来访问此 Cookie。
  • Secure: 该 Cookie 是否仅被使用安全协议传输。安全协议有 HTTPS 和 SSL 等,在网络上传输数据之前先将数据加密。默认为 false。

代理的基本原理

在我们正常请求一个网站时,我们直接把请求发给了Web服务器,Web服务器又直接把响应回传给我们。

而如果我们使用 代理服务,就等于是多了一个中间人,即代理服务器,这个过程变成了: 我们直接把请求发给 代理服务器,代理服务器 把响应回传给 代理服务器,代理服务器再把这个消息传给我们。

通过代理,我们就可以伪装IP,防制在爬虫时被查出来封IP或事需要提供验证码,影响爬虫运行。

⚠️【注意】并不是所有的 代理 都可以让我们隐藏 IP! 有的 代理服务 会在向 web服务器 的请求 时,不会原封不动的转发我们的消息,而是在其中添加上我们的真实IP等信息,这时就隐藏不了了。