笔记之Python网络数据采集

笔记之Python网络数据采集

  • 非原创即采集
  • 一念清净, 烈焰成池, 一念觉醒, 方登彼岸
  • 网络数据采集, 无非就是写一个自动化程序向网络服务器请求数据, 再对数据进行解析, 提取须要的信息
  • 一般, 有api可用, api会比写网络爬虫程序来获取数据更加方便.

Part1 建立爬虫

Chapter1 初建网络爬虫

  • 一旦你开始采集网络数据, 就会感觉到浏览器为咱们所作的全部细节, 它解释了全部的html, css, JavaScript
  • 网络浏览器是一个很是有用的应用, 它建立信息的数据包, 发送, 并把获取的数据解释成图像, 声音, 视频, 或文字. 但网络浏览器就是代码, 而代码是能够分解的, 能够分解成许多基本组件, 可重写, 重用, 以及作成咱们想要的任何东西
  • “域名为kissg.me的服务器上<网络应用根地址>/pages目录下的html文件page1.html的源代码"
  • 网络浏览器与爬虫程序的区别:
  • 浏览器遇到html标签时, 会向服务器再发起对该资源的请求, 再用请求获得的资源渲染页面
  • 爬虫程序并无返回向服务器请求多个文件的逻辑, 它只能读取已经请求的单个html文件
  • BeautifulSoup经过定位html标签来格式化和组织复杂的网络信息, 以python对象展现xml结构信息
  • 先调用response.read()获取网页的内容, 再将html内容传给BeautifulSoup对象, 造成的结构以下所示:
html <html><head>...</head><body>...</body></html> - head <head><title>A Useful Page<title></head> - title <title>A Useful Page</title> - body <body><h1>An Int...</h1><div>Lorem ip...</div></body> - h1 <h1>An Interesting Title</h1> - div <div>Lorem Ipsum dolor...</div> 
  • 所以能够经过bsObj.html.body.h1的方式提取标签
  • 请求的网页在服务器上不存在时, 程序会返回http错误, urlopen函数会抛出HTTPError异常, 对此, 可以使用try ... except ...语句来处理
  • 服务器不存在, urlopen返回一个None对象, 可经过条件判断简单地处理
  • 当调用的标签不存在时, BeautifulSoup会返回None对象, 请求None对象的子标签, 会发生AttributeError错误, 一样地, 也用try ... except ... 语句来处理
  • 一个良好的爬虫程序首先要具有强大而周密的异常处理能力, 随时应对网络中可能存在的异常
  • 在写爬虫的时候, 思考代码的整体格局, 让代码既能够捕捉异常又容易阅读, 很重要. 考虑代码的重用性

Chapter2 复杂html解析

  • 当米开朗基罗被问及如何完成”大卫”这样匠心独具的雕刻做品时, 他有一段著名的回答: “很简单, 你只要用锤子把石头上不像大卫的地方敲掉就好了.” (大道至简)
  • 解析html的前戏, 磨刀不勿砍柴功:
    1. 寻找”打印此页”, 或看看网站有没有html样式更友好的移动版(将请求头设置成移动设备的状态, 而后接收网站移动版)
    2. 需找隐藏在js文件里的信息,
    3. 网页信息也许能够从网页的url连接中获取
    4. 寻找其余数据源, 有没有其余网站显示了一样的数据? 该网站的数据是否是来自其余网站
  • css(cascading style sheet, 层叠样式表)为爬虫提供了便利, 它是html元素差别化, 使那些具备相同修饰的元素呈现不一样的样式, 从而是爬虫的目标更明确
  • findAll()的基础用法: findAll(tag_name, dict_of_attributes)
  • 使用bsObj.tagName只能获取页面中第一个指定的标签
  • get_text()方法正在处理的html文档中的全部标签都清楚掉, 返回只包含文字的字符串
  • findAll(tag, attributes, recursive, text, limit, **keywords) & find(tag, attributes, recursive, text, **keywords):
  • tag - 能够是单个标签名, 也能够是多个标签名组成的列表(集合)
  • attributes - 用字段封装的标签属性与属性值, 属性值能够是一个集合
  • recursive - 递归? 默认为True. 若recursive=False, findAll只会查文档的一级标签. 若对速度要求很是高, 可设置递归参数
  • text - 用标签的内容去匹配, 而不是标签名或属性,
  • limit - 限制findAll的搜索结果项
  • 关键字参数 - 容许用户本身指定属性的标签. 是BeautifulSoup在技术上作的冗余功能, 任何关键字参数能完成的任务, 均可以其余技术解决
  • 经过标签参数tag把标签列表传到.findAll()里获取一列标签, 实际上是一个”或”关系的过滤器. 而关键字参数能够增长一个”与”关系的过滤器来简化工做
  • Tag对象 - BeautifulSoup对象经过findfindAll, 或直接调用子标签获取的一些列对象或单个对象
  • NavigableString对象 - 用于表示标签里的文字
  • Comment对象 - html文档的注释标签
  • html页面能够映射成一棵树
  • 子标签, 即一个父标签的下一级; 后代标签, 指一个父标签下面全部级别的标签. 全部子标签都是后代标签, 但不是全部的后代标签都是子标签
  • 通常, bs函数老是处理当前标签的后代标签, 好比.findAll就是递归地在全部后代标签中查找
  • 使用.children将只获取当前标签的子标签, 使用descendants将获取全部后代标签
  • 使用.next_siblings将得到当前标签以后,全部的兄弟标签. 注意, 对象自己不能做为本身的兄弟标签; 从名字也能够看出, 是返回以后的兄弟标签. 相应的有previous_siblings,next_siblingprevious_sibling
  • 使用bsObj.find("table", {"id": "giftList"}).tr而不是简单的bsObj.table.trbsObj.tr是为了让对象的选择更具体, 而不丢失标签的细节
  • parentparents分别用于获取标签对象的直接父标签和全部父辈标签(包括爷爷, 但不包括叔叔, 好吧, 通俗易懂)
  • 在动手写正则表达式以前, 写一个步骤列表描述出目标字符串的结构
  • regex:
  • * - 重复任意次, 包括0次
  • | - 表示或
  • + - 重复至少1次
  • [] - 匹配其中的任意一个字符
  • () - 表达式编组, 在regex的规则里编组会优先运行
  • {m,n} - 重复m到n次
  • [^] - 匹配一个任意不在方括号中的字符
  • . - 匹配任意单个字符
  • ^ - 标识字符串的开始
  • \ - 转义字符
  • $ - 标识字符串的结尾
  • 在BeautifulSoup中使用regex, 提升效率, 如images = bsObj.findAll("img",{"src":re.compile("\.\.imggifts/img.*\.jpg")})
  • regex能够做为BeautifulSoup语句的任意一个参数
  • 对于标签对象, 可采用.attrs获取所有属性, 返回字典对象. imgTag.attrs["src"]就能够获取图片的资源位置
  • BeautifulSoup容许将特定函数类型做为findAll函数的参数, 惟一的限制条件是这些函数必须将一个标签做为参数返回结果是布尔类型. BeautifulSoup用这个函数评估遇到的每一个标签对象, 将评估结果为”True”的标签保留下来, 将其余标签剔除. 如soup.findAll(lambda tag: len(tag.attrs) == 2)将返回具备2个属性的标签
  • BeautifulSoup与regex与lambda的联合使用, 想一想都无敌
  • 其余的html解析模块:
    1. lxml - 底层, 大部分源代码用c写成, 所以处理速度会很是快
    2. HTML parser - 自带的

Chapter3 开始采集

  • 之因此叫网络爬虫, 是由于他们能够沿着网络爬行, 本质是一种递归方式: 为了找到url连接, 必须首先获取网页内容, 检查页面内容, 再寻找另外一个url, 获取页面内容, 不断循环
  • 使用网络爬虫的时候, 应谨慎地考虑须要消耗多少网络流量, 还要尽可能思考可否让采集目标的服务器负载更低
  • 维基百科六度分隔理论 - 任何2个不相干的词条, 均可以经过总数不超过6条的词条连接起来(包括原来的2个词条).
  • 由此, 写爬虫时, 如何高效地经过最少的连接点击次数到达目的站点, 不只使爬虫工做效率更高, 且对服务器的负载影响也越小
  • 爬取的内容每每携带许多无用的信息, 在处理以前, 应根据实际剔除无用信息
  • 随机算法都努力创造一种均匀分布且难以预测的数据序列, 但在算法初始阶段都须要提供一个随机数种子(random seed). 彻底相同的种子每次将产生相同的”随机”数序列. 能够用系统当前时间做为随机数种子, 而使程序运行更具随机性.
  • python的伪随机数生成器用的是梅森旋转算法(https://en.wikipedia.org/wiki/Mersenne_Twister)
  • 浅网(surface web)是搜索引擎能够抓取的网络; 暗网(dark web)或深网(deep web)则是另外一部分. 据不彻底统计,互联网中其实约 90% 的网络都是深网.
  • 暗网,也被称为 Darknet 或 dark Internet,彻底是另外一种“怪兽”。它们也创建在已有的网络基础上,可是使用 Tor 客户端,带有运行在 HTTP 之上的新协议,提供了一个信息交换的安全隧道。这类暗网页面也是能够采集的。
  • 遍历整个网站的数据采集的好处:
    1. 生成网站地图(脉络)
    2. 收集数据
  • 为了不重复采集页面, 使用set来保存已采集的页面
  • 若是递归运行的次数过多, 递归程序可能会崩溃. python的默认递归限制是1000次.
  • 在开始写爬虫程序以前, 应充分分析待爬取网站的html文档的格式
  • 在一个异常处理语句中包裹多行语句显然是有点危险的. 首先没法识别出究竟哪行代码出现了异常, 其次前面的语句出现异常, 将直接致使后面语句的执行
  • 网络爬虫位于许多新式的网络技术领域彼此交叉的中心地带. 要实现跨站的数据分析, 只要构建出能够从互联网上的网页里解析和存储数据的爬虫就能够了
  • 一个网站内部的爬虫, 只须要爬取以/开始的资源就能够了
  • 在开始写爬虫跟随外链随意跳转以前, 该思考的问题:
  • 我要收集哪些数据?这些数据能够经过采集几个已经肯定的网站(永远是最简单的作法)完成吗?或者个人爬虫须要发现那些我可能不知道的网站吗?
  • 当个人爬虫到了某个网站,它是当即顺着下一个出站连接跳到一个新网站,仍是在网站上呆一下子,深刻采集网站的内容?
  • 有没有我不想采集的一类网站?我对非英文网站的内容感兴趣吗?
  • 若是个人网络爬虫引发了某个网站网管的怀疑,我如何避免法律责任?
  • 在以任何正式目的运行代码以前, 确保已经在可能出现问题的地方都放置了检查语句
  • 写代码以前拟个大纲或画个流程图, 是一个很好的编程习惯, 不只能够为后期处理节省时间, 更重要的是能够防止本身在爬虫变得愈来愈复杂时乱了分寸
  • 重定向 - 容许一个网页在不一样的域名下显示, 有2种形式:
    1. 服务器端重定向, 网页在加载以前先改变了url
    2. 客户端重定向, 跳转到新url以前网页须要加载内容
  • python3版本的urllib库会自动处理重定向. 不过要注意,有时候要采集的页面的 URL 可能并非当前所在页面的url
  • 爬虫的一些基本模式: 找出页面上的全部连接, 区份内外链, 跳转到新的页面

Chapter4 使用API

  • API的用处:为不一样的应用提供了方便友好的接口。不一样的开发者用不一样的架构,甚至不一样的语言编写软件都没问题——由于API设计的目的就是要成为一种通用语言,让不一样的软件进行信息共享。
  • API 能够经过 HTTP 协议下载文件,和 URL 访问网站获取数据的协议同样,它几乎能够实现全部在网上干的事情。API 之因此叫 API 而不是叫网站的缘由,实际上是首先 API 请求使用很是严谨的语法,其次 API 用 JSON 或 XML 格式表示数据,而不是HTML 格式。
  • 一般api的验证方法都是用相似令牌(token)的方式调用, 每次api调用将令牌传递给服务器. token除了在url连接中传递, 还会经过请求头里的cookie将用户信息传递给服务器:
token = token
webRequest = urllib.request.Request("http://xxx", headers={"token": token})
  • api一个重要的特征是反馈格式友好的数据, xml或json. 目前json比xml更受欢迎, 由于json文件比完整的xml文件小, 另外一个缘由是网络技术的改变.
  • 使用get请求获取数据时, 用url路径描述获取的数据范围, 查询参数能够做为过滤器或附加请求使用.
  • 一些api使用文件路径形式指定api版本, 数据和其余属性:
http://socialmediasite.com/api/v4/json/users/1234/posts?from=08012014&to=08312014
  • 一些api经过请求参数的形式指定数据格式和api版本:
http://socialmediasite.com/users/1234/posts?format=json&from=08012014&to=08312014
  • response.read() -> bytes
  • python将json转换成字典, json数组转换成列表, json字符串转换成pyton字符串
  • 若是你用API做为惟一的数据源,那么你最多就是复制别人数据库里的数据,不过都是些已经公布过的“黄花菜”。真正有意思的事情,是把多个数据源组合成新的形式,或者把 API 做为一种工具,从全新的视角对采集到的数据进行解释
  • 虽然列表迭代速度更快, 但集合查找速度更快(肯定一个对象是否在集合中).
  • python的集合就是值为None的字典, 用到是hash表结构, 查询速度为O(1)
  • 多种技术的融合, 多种数据的融合, 将获得更有用的信息

Chapter5 存储数据

  • 大数据存储与数据交互能力, 在新式的程序开发中已是重中之重了.
  • 存储媒体文件的2种主要方式: 只获取url连接, 或直接将源文件下载下来
  • 直接引用url连接的优势:
  • 爬虫运行得更快,耗费的流量更少,由于只要连接,不须要下载文件。
  • 能够节省不少存储空间,由于只须要存储 URL 连接就能够。
  • 存储 URL 的代码更容易写,也不须要实现文件下载代码。
  • 不下载文件可以下降目标主机服务器的负载。
  • 直接引用url连接的缺点:
  • 这些内嵌在网站或应用中的外站 URL 连接被称为盗链(hotlinking), 每一个网站都会实施防盗链措施。
  • 由于连接文件在别人的服务器上,因此应用就要跟着别人的节奏运行了。
  • 盗链是很容易改变的。若是盗链图片放在博客上,要是被对方服务器发现,极可能被恶搞。若是 URL 连接存起来准备之后再用,可能用的时候连接已经失效了,或者是变成了彻底无关的内容。
  • python3的urllib.request.urlretrieve能够根据文件的url下载文件:
from urllib.request import urlretrieve from urllib.request import urlopen from bs4 import BeautifulSoup html = urlopen("http://www.pythonscraping.com") bsObj = BeautifulSoup(html) imageLocation = bsObj.find("a", {"id": "logo"}).find("img")["src"] urlretrieve (imageLocation, "logo.jpg") 
  • csv(comma-separated values, 逗号分隔值)是存储表格数据的经常使用文件格式
  • 网络数据采集的一个经常使用功能就是获取html表格并写入csv
  • 除了用户定义的变量名,mysql是不区分大小写的, 习惯上mysql关键字用大写表示
  • 链接与游标(connection/cursor)是数据库编程的2种模式:
  • 链接模式除了要链接数据库以外, 还要发送数据库信息, 处理回滚操做, 建立游标对象等
  • 一个链接能够建立多个游标, 一个游标跟踪一种状态信息, 好比数据库的使用状态. 游标还会包含最后一次查询执行的结果. 经过调用游标函数, 如fetchall获取查询结果
  • 游标与链接使用完毕以后,务必要关闭, 不然会致使链接泄漏, 会一直消耗数据库资源
  • 使用try ... finally语句保证数据库链接与游标的关闭
  • 让数据库更高效的几种方法:
    1. 给每张表都增长id字段. 一般数据库很难智能地选择主键
    2. 用智能索引, CREATE INDEX definition ON dictionary (id, definition(16));
    3. 选择合适的范式
  • 发送Email, 经过爬虫或api获取信息, 设置条件自动发送Email! 那些订阅邮件, 确定就是这么来的!

Chapter6 读取文档

  • 互联网的最基本特征: 做为不一样类型文件的传输媒体
  • 互联网不是一个html页面的集合, 它是一个信息的集合, 而html文件只是展现信息的一个框架
  • 从最底层的角度看, 全部文档都是01的编码, 而任意类型的文件的惟一区别就在于,它们的01在面向用户的转换方式不一样
  • utf-8的全称: Universal Character Set - Transformation Format 8 bit
  • utf-8的每一个字符开头有一个标记,表示该字符用几个字节表示.一个字符最多能够是4字节, 但字节信息里还包括一部分设置信息, 所以所有32位不会都用, 最多使用21位
  • utf8利用ascii的填充位让全部以”0”开头的字节表示该字符占用1个字节. 所以, 在英文字符在ascii和uft8两个编码方式下表示同样
  • python默认将文本读成ascii编码格式
  • utf8不能处理iso编码格式. 所以作数据采集工做时,尤为对国际网咱, 最好先看看meta标签内容, 用网站推荐的编码方式读取页面内容
  • 几种读取在线文件的方法:
    1. 下载读取
    2. 从网上直接将文件读成一个字符串, 而后将其转换成一个StringIO对象, 使其具备文件的属性:
dataFile = io.StringIO(data) 
  • csv.reader的返回对象是可迭代的, 并且由list对象构成.
  • csv.DictReader将csv文件的每一行转换成python字典返回, 并将字段列表(标题栏)保存在dictReader.fieldnames里
  • pdf的文字提取
  • .docx的文字提取:
    1. 从文件读取xml, 将文档读成一个二进制对象(BytesIO), 再用zipfile解压(全部.docx文件为了节省空间都进行过压缩), 再读取解压文件, 就变成了xml
from zipfile import ZipFile from urllib.request import urlopen from io import BytesIO wordFile = urlopen("http://pythonscraping.com/pages/AWordDocument.docx").read() wordFile = BytesIO(wordFile) document = ZipFile(wordFile) xml_content = document.read("word/document.xml") print(xml_content.decode("utf-8")) 

Part2 高阶数据采集

  • 网站的真实故事其实都隐藏在js, 登陆表单和网站反爬取措施的背后

Chapter7 数据清洗

  • 用regex移除不想要的字符, 如换行符(\n). 剔除字符的过程, 合理的前后顺序能省不少力
  • 先以utf8格式编码,再以ascii方法解码的方式,能够必定程度上剔除unicode字符
  • 数据标准化要确保清洗后的数据在语言学或逻辑上是等价的
  • python的OrderedDict,能解决字典无序排列的问题
  • 数据标准化时,根据投入计算能力的多少,还能够再考虑大小写(python与Python),单词等价(1st与first),连字符的使用(co-ordinated与coordinated),拼写错误,语病等因素
  • 对连字符的一个处理是,将其去掉或转换成其余字符,好比空格

Chapter8 天然语言处理

归纳数据

  • n-gram模型可用于词频分析, 很厉害!

马尔可夫模型

  • 马尔可夫文字生成器(markov text generator) - 基于一种经常使用于分析大量随机事件的马尔可夫模型. 随机事件的特色是一个离散事件发生以后, 另外一个离散事件将在前一个事件的条件下以必定几率发生
  • 在马尔可夫模型描述的天气系统中,若是今天是晴天,那么明天有70%的多是晴天,20%的可能多云,10% 的可能下雨。若是今天是下雨天,那么明天有 50% 的可能也下雨,25% 的多是晴天,25% 的多是多云
  • 马尔可夫模型须要注意的点:
  • 任何一个节点引出的全部可能的总和必须等于 100%。不管是多么复杂的系统,必然会在下一步发生若干事件中的一个事件。
  • 只有当前节点的状态会影响下一个状态。
  • 有些节点可能比其余节点较难到达
  • google的pagerank算法也是基于马尔可夫模型的, 将网站看做节点, 入站/出站连接做为节点的连线. 链接某个节点的可能性(linklihood)表示一个网站的相对关注度
  • 马尔可夫文字生成器的工做原理: 对文献中的每个单词进行有效处理, 再创建一个二维字典, 用于统计二元词组的词频. 每次以当前单词所在节点为查询表, 选择下一个节点. 随机生成一个权重, 用词频减权重, 一旦权重减为非正数, 肯定该单词为下一单词. 词频高的单词使权重减少得更厉害, 所以更容易得到
  • 在寻找有向图的最短路径问题中, 效果最好且最经常使用的方法是广度优先搜索(breadth-first search, bfs)

天然语言处理

  • 哪些单词使用得最频繁?哪些单词用得最少?一个单词后面跟着哪几个单词?这些单词是如何组合在一块儿的?
  • nltk, 用于识别和标记英语文本中各词的词性.
  • nltk很擅长生成一些统计信息,包括对一段文字的单词数量单词频率单词词性的统计
  • 用nltk作统计分析通常从Text对象开始`
from nltk import word_tokenize from nltk import Text tokens = word_tokenize("Here is some not very interesting text") text = Text(tokens) 
  • word_tokenize函数的参数能够是任何python字符串, 其将字符串按语义分割成单词
  • 文本对象能够像普通的python list那样操做, 好像它们就是一个包含文本里全部单词的list同样.
  • 将文本对象放到一个频率分布对象FreqDist中, 可查看哪些单词是最经常使用的, 以及单词的频率等
  • bigrams模块的bigrams函数做用于文本对象, 获得一个bigrams(2-gram)的生成器对象, 其也能够做为参数传入FreqDist, 获得频率分布对象
  • 更通常的状况, 能够导入ngrams模块, ngrams函数被用来将文本对象分解成任意规模的n-gram序列,
  • nltk库设计了许多不一样的工具和对象来组织, 统计, 排序和度量大段文字的含义
  • nltk默认使用宾夕法尼亚大学Penn Treebank项目的语料标记部分
  • nltk能够用它的超级大字典分析文本内容, 帮助寻找单词的含义. nltk的一个基本功能是识别句子中各个词的词性
  • nltk用英语的上下文无关文法(context-free grammar)识别词性. 上下文无关文法基本上能够当作一个规则集合,用一个有序的列表肯定一个词后面能够跟哪些词
  • nltk进行训练, 建立一个全新的上下文无关文法规则, 好比用Penn Treebank词性标记手工完成语言的大部分文本的语义标记, 将结果传给nltk, 训练它对未标记文本的语义标记.
  • 网络数据采集常常须要处理搜索的问题, 好比采集的文字的词性, 举例, 但愿采集是动词飞的fly, 而过滤掉名词苍蝇的fly
  • 天然语言中的许多歧义问题均可以用nltkpos_tag解决, 不仅是搜索目标单词或短语, 而是搜索带标记的目标单词或短语,这样能够大大提升爬虫搜索的准确率和效率

Chapter9 穿越网页表单与登陆窗口进行采集

  • 利用post方法, 将信息推送到服务器进行存储与分析
  • 页面表单基本上能够当作一种用户提交post请求的方式, 且这种请求方式是服务器可以理解和使用的

Requests库

  • Requests库是一个擅长处理复杂的http请求, cookie, header等内容的第三方库

提交一个基本表单

  • 大多数网页表单都是由一些 HTML 字段、一个提交按钮、一个在表单处理完以后跳转的“执行结果”(表单属性 action 的值)页面构成。
  • 字段的名称决定了表单被确认后要被传送到服务器上的变量名称
  • 表单的真实行为发生在action指定的页面
  • HTML 表单的目的,只是帮助网站的访问者发送格式合理的请求,向服务器请求没有出现的页面
  • 大多数状况下, 提交表单只须要注意:
    1. 提交数据的字段名称
    2. 表单的action属性, 即表单提交后网站会显示的页面

单选按钮, 复选框和其余输入

  • 不管表单的字段看起来多么复杂,仍然只有两件事是须要关注的:字段名称。字段名称能够经过查看源代码寻找 name 属性轻易得到
  • 字段的值有时会比较复杂. 若是不肯定一个输入字段指定数据格式, 可跟踪浏览器正在经过网站发出或接受的get和post请求的内容.
  • 跟踪get请求效果最好也最直接的手段是看网站的url连接, ?xxx=xxx&xxx=...
  • 复杂的post表单, 可查看浏览器向服务器传递的参数, 用chrome的F12

提交文件和图像

  • requests处理文件上传的方式与提交普通表单相似:
import requests file = {"image": open("filename", "rb")} response = requests.post("http://...", data = file) 
  • 大多数新式的网站都用 cookie 跟踪用户是否已登陆的状态信息。一旦网站验证了登陆权证,它就会将它们保存在浏览器的 cookie 中,里面一般包含一个服务器生成的令牌登陆有效时限状态跟踪信息。网站会把这个 cookie 看成信息验证的证据,在你浏览网站的每一个页面时出示给服务器。
  • obj.cookies.method从响应中获取cookie, 再经过cookies参数将cookie发送给服务器
  • 使用session对象, 能够持续跟踪会话信息, 好比cookie, header, 甚至运行http协议的信息.
  • 使session的方法就是, 建立Session对象, 再用Session对象发送请求
  • 写爬虫时, 应持续关注cookie的状态, 掌握它们在可控范围内很是重要. 这样能够避免痛苦地调试和追寻网站行为异常,节省不少时间。
  • 在cookie发明以前, 处理网站登陆经常使用的方法是用http基本接入认证(http basic access authentication), requests库的auth模块专门用来处理http认证:
import requests from requests.auth import AuthBase from requests.auth import HTTPBasicAuth auth = HTTPBasicAuth('ryan', 'password') r = requests.post(url="http://pythonscraping.com/pages/auth/login.php", auth=auth) # HTTPBasicAuth对象做为auth参数传递到请求 

其余表单问题

  • 表单是网络恶意机器人(malicious bots)酷爱的网站切入点。
  • 新式的网站常常在HTML 中使用不少安全措施,让表单不能被快速穿越

Chapter10 采集 JavaScript

  • JavaScript 是网络上最经常使用也是支持者最多的客户端脚本语言。它能够收集用户的跟踪数据,不须要重载页面直接提交表单,在页面嵌入多媒体文件,甚至运行网页游戏

JavaScript 简介

  • JavaScript 是一种弱类型语言, 全部变量都用var关键字进行定义, 能够将函数做为变量使用
  • 经常使用的 JavaScript 库
    1. jQuery:
      • 一个网站使用jQuery的特征是源代码里包含了jQuery入口.
      • jQuery 能够动态地建立 HTML 内容,只有在 JavaScript 代码执行以后才会显示。若是用传统的方法采集页面内容,就只能得到 JavaScript 代码执行以前页面上的内容
      • 这些页面还可能包含动画、用户交互内容和嵌入式媒体,这些内容对网络数据采集都是挑战。
    2. Google Analytics
      • 若是网站使用了Google Analytics,在页面底部会有相似<!-- Google Analytics -->的 JavaScript 代码
      • 若是一个网站使用了 Google Analytics 或其余相似的网络分析系统,而不想让网站知道在采集数据,就要确保把那些分析工具的 cookie 或者全部 cookie 都关掉。
    3. Google Map
      • 在 Google 地图上,显示一个位置最经常使用的方法就是用标记
var marker = new google.maps.Marker({
    position: new google.maps.LatLng(-25.363882,131.044922),
    map: map,
    title: 'Some marker text'
});
  • 取出google.maps.LatLng()里的坐标, 生成一组经纬度坐标值, 再经过google的地理坐标反向查询api(https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse), 就能够将经纬度坐标组解析成格式规范的地址, 可存储或分析

ajax和动态html

  • 提交表单以后,或从服务器获取信息以后,网站的页面不须要从新刷新,那么访问的网站就在用 Ajax 技术。
  • Ajax(Asynchronous JavaScript and XML) 其实并非一门语言,而是用来完成网络任务的一系列技术, 网站不须要使用单独的页面请求就能够和网络服务器进行交互
  • 动态 HTML(dynamic HTML,DHTML)也是一系列用于解决网络问题的技术集合。DHTML 是用客户端语言改变页面的 HTML 元素(HTML、CSS,或者两者皆被改变). 是否使用了DHTML, 关键要看有没有用 JavaScript 控制 HTML 和 CSS 元素
  • 有时,网页用一个加载页面把你引到另外一个页面上,可是网页的 URL 连接在这个过程当中一直没有变化。
  • 当用爬虫采集的网页内容与浏览器上显示的不一样时, 是由于爬虫不能执行 JavaScript 代码, 而浏览器能够正确地执行 JavaScript .
  • 用python爬取使用了ajaxdhtml的页面的2种办法:
    1. 直接从 JavaScript 代码里采集内容
    2. 用第三方库运行 JavaScript , 直接采集在浏览器中看到的页面

Selenium

  • Selenium是一个网络数据采集工具, 其最初是为网站自动化测试而开发的, 近几年,它还被普遍用于获取精确的网站快照.
  • Selenium能够直接运行在浏览器上, 它可让浏览器自动加载页面, 获取须要的数据, 甚至页面截屏, 或者判断网站上某些动做是否发生
  • Selenium须要与第三方浏览器结合使用.
  • PhantomJS能够将网站加载到内存并执行页面上的 JavaScript, 但它不会向用户展现网页的图形界面.
  • 把 Selenium 和 PhantomJS 结合在一块儿,就能够运行一个很是强大的网络爬虫了,能够处理cookieJavaScripheader,以及任何须要作的事情
  • python的Selenium库是一个在WebDriver上调用的api, webdriver有点像加载网站的浏览器, 能够像BeautifulSoup对象同样用来查找页面元素, 与页面上的元素进行交互, 以及执行其余动做来运行爬虫
  • webdriver的page_source函数返回页面的源代码字符串. 若不想要Selenium选择器, 则能够用返回的源代码建立BeautifulSoup对象.
  • 页面的加载时间是不肯定的, 具体依赖于服务器某一毫秒的负载状况, 以及不断变化的网速
  • 解决页面加载时间不肯定的有效方法是, 让Selenium不断检查某个元素是否存在, 以肯定页面是否彻底加载, 若是页面加载成功, 就执行后续程序.
  • WebDriverWaitexpected_conditions组合构成了Selenium的隐式等待(implicit wait).
  • 隐式等待显式等待的不一样之处在于,隐式等待是等 DOM 中某个状态发生后再继续运行代码(没有明确的等待时间,可是有最大等待时限,只要在时限内就能够),而显式等待明确设置了等待时间。在隐式等待中,DOM 触发的状态用expected_conditions 定义
  • Selenium中元素被触发的指望条件有许多种, 包括
  • 弹出一个提示框
  • 一个元素被选中(好比文本框)
  • 页面的标题改变了,或者某个文字显示在页面上或者某个元素里
  • 一个元素在 DOM 中变成可见的,或者一个元素从 DOM 中消失了
  • 大多数指望的条件在使用前须要指定等待的目标元素, 元素用定位器指定.
  • 定位器是一种抽象的查询语言,用 By 对象表示,能够用于不一样的场合,包括建立选择器(driver.find_element(By.ID, “content”))
  • 若是能够不用定位器, 就不用, 毕竟能够少导入一个模块
  • Xpath(XML Path)是在xml文档中导航和选择元素的查询语言. BeautifulSoup不支持Xpath. 使用方法一般和css选择器同样.
  • Xpath语法中四个重要概念:
    1. 根节点与非根节点
      • /div 选择 div 节点,只有当它是文档的根节点时
      • //div 选择文档中全部的 div 节点(包括非根节点)
    2. 经过属性选择节点
      • //@href 选择带 href 属性的全部节点
      • //a[@href=’http://google.com’] 选择页面中全部指向 Google 网站的连接
    3. 经过位置选择节点
      • //a[3] 选择文档中的第三个连接
      • //table[last()] 选择文档中的最后一个表
      • //a[position() < 3] 选择文档中的前三个连接
    4. *(星号)匹配任意字符或节点, 能够在不一样条件下使用
      • //table/tr/* 选择全部表格行 tr 标签的全部的子节点(这很适合选择 th 和 td 标签)
      • //div[@*] 选择带任意属性的全部 div 标签
  • 微软的Xpath语法页面https://msdn.microsoft.com/en-us/enus/library/ms256471

处理重定向

  • 客户端重定向是在服务器将页面内容发送到浏览器以前,由浏览器执行 JavaScript 完成的页面跳转,而不是服务器完成的跳转
  • 客户端重定向redirect, 即服务器在返回的响应中告知客户端请求资源的正确url, 并设置状态码3xx. 客户端根据响应结果对新的url发起请求
  • 服务器重定向dispatch, 指服务器在处理请求的过程当中将请求前后分发(委托)给其余部件处理的过程. 服务器内部如何操做, 不能知道也不须要知道吧
  • 服务器重定向可经过python的urllib库解决
  • 利用Selenium执行 JavaScript 代码, 解决客户端重定向问题. 关键点在于什么时候中止页面监控. 一种方法是: 从页面开始加载时就“监视”DOM 中的一个元素,而后重复调用这个元素直到Selenium抛出一个StaleElementReferenceException异常;也就是说,元素不在页面的 DOM 里了,说明这时网站已经跳转

Chapter11 图像识别与文字处理

  • 当不想让文字被爬虫采集时, 将文字作成图片放在网页上是经常使用的方法

OCR(Optical Character Recognition, 光学文字识别)

  • 利用Pillow完成图片的预处理, 让机器能够更方便地读取图片
  • Tesseract是一个ocr库, 高精确度, 高灵活性, 能够经过训练识别出任何字体以及任何unicode字符
  • Tesseract是一个python的命令行工具, 经过tesseract命令在python外运行
  • NumPy库具备大量线性代数以及大规模科学计算的方法, 其能够用数学方法将图片表示成巨大的像素数组

处理格式规范的文字

  • 格式规范的文字的特色:
  • 使用一个标准字体(不包含手写体、草书,或者十分“花哨的”字体)
  • 虽然被复印或拍照,字体仍是很清晰,没有多余的痕迹或污点
  • 排列整齐,没有歪歪斜斜的字
  • 没有超出图片范围,也没有残缺不全,或牢牢贴在图片的边缘
  • 对于难于辨认的图片, 先对图片进行预处理, 可大大提升图文转换的正确率
  • Tesseract最大的缺点是对渐变背景色的处理, 它的算法在读取文件以前自动尝试调整图片对比度
  • 使用Selenium + Tesseract从网站图片中抓取文- 对于难于辨认的图片, 先对图片进行预处理, 可大大提升图文转换的正确率
  • 经过给 Tesseract 提供大量已知的文字与图片映射集,通过训练 Tesseract 就能够“学会”识别同一种字体,并且能够达到极高的精确率和准确率,甚至能够忽略图片中文字的背景色和相对位置等问题。

读取验证码与训练Tessract

  • CAPTCHA(Completely Automated Public Turing test to tell Computers and Humans Apart, 全自动区分计算机与人类的图灵测试), 简称验证码, 其目的是为了阻止网络访问
  • 要训练Tesseract识别一种文字, 都须要向其提供每一个字符不一样形式的样本:
    1. 将大量验证码样本下载到一个目录, 样本数量由验证码的复杂程度决定.(用验证码的真实结果给每一个样本文件命名)
    2. 准确地告诉tesseract一张图片中的每一个字符是什么, 以及每一个字符的具体位置. 这时要建立一些矩形定位文件, 一个验证码图片生成一个矩形定位文件(字符 + 包围字符的最小矩形的左下角和右上角坐标 + 图片样本的编号)(http://pp19dd.com/tesseract-ocr-chopper/ 在线转换工具)
    3. 矩形定位文件必须保存为一个.box的文本文件, 一样用验证码的实际结果命名
    4. 备份
    5. 用同时包含验证码图片和.box文件的目录, 建立训练文件, 即.tessdata文件

获取验证码提交答案

  • 大多数网站生成的验证码图片都具备如下属性。
  • 它们是服务器端的程序动态生成的图片。验证码图片的 src 属性可能和普通图片不太同样,可是能够和其余图片同样进行下载和处理。
  • 图片的答案存储在服务器端的数据库里。
  • 不少验证码都有时间限制,若是你太长时间没解决就会失效。虽然这对网络机器人来讲不是什么问题,可是若是你想保留验证码的答案一下子再使用,或者想经过一些方法延长验证码的有效时限,可能很难成功。
  • 经常使用的处理方法就是,首先把验证码图片下载,清理干净,而后用 Tesseract 处理图片,最后返回符合网站要求的识别结果。

Chapter12 避开采集陷阱

道德规范

  • 在采集那些不想被采集的网站时, 可能存在一些很是符合道德和法律规范的理由
  • 大多数网络机器人一开始都只能作一些宽泛的信息和漏洞扫描

让网络机器人看起来像人类用户

  • requests模块除了处理网站的表单, 仍是设置请求首部的利器.
  • 7个被大多数浏览器用来初始化全部网络请求的请求报文首部字段:
    1. Host : http://kissg.me
    2. Connection : keep-alive
    3. Accept : text/html,application/xhtml+xml,application/xml;q=0.9,image/webp
    4. User-Agent : Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_5) AppleWebKit/537.36 (KHTML, likeGecko) Chrome/39.0.2171.95 Safari/537.36
    5. Referrer : https://kissg.me/
    6. Accept-Encoding : gzip,deflate,sdch
    7. Accept-Language : en-US,en
  • 经典的python爬虫在使用urllib标准库时, 都会发送Accept-Encoding=identity;User-Agent=Python-urllib/3.4的请求头
  • 虽然网站可能会对http请求首部的每一个字段进行”是否具备人性”的检查, 但最重要的参数是”User-Agent”
  • 在处理一些警觉性很是高的网站, 要注意常常用却不多检查的首部字段, 好比Accept-Language
  • 请求头的不一样, 可让网站改变内容的布局, 好比User-Agent设置成移动设备的首部, Accpet-Language设置成另外一种语言
  • 可 以 调 用 delete_cookie() 、 add_cookie() 和 delete_all_cookies() 方 法 来 处 理cookie。另外,还能够保存 cookie 以备其余网络爬虫使用
  • 有时候须要增长时延, 来使爬虫假装得更像人类
  • 多线程爬虫, 一个线程处理数据, 另外一个加载数据(我之前想的提升爬取速度的方法大体也是这样)

常见表单安全措施

  • 在html表单中, 隐含字段可让字段对浏览器可见, 而对用户不可见. 随着愈来愈多的网站开始用 cookie 存储状态变量来管理用户状态,在找到另外一个最佳用途以前,隐含字段主要用于阻止爬虫自动提交表单
  • 用隐含字段阻止网络数据采集的2种方式:
    1. 使表单页面上的一个字段能够用服务器生成的随机变量表示. 解决办法就是先采集表单页面上的这个随便变量, 再与其余表单数据一并提交
    2. 蜜罐(honey pot), 故意设一个隐含字段, 服务器将自动忽略这些字段的真实值, 但全部填写了隐含字段的用户可能被封杀. 说白了, 就是为爬虫故意设的字段, 通常用户看不到, 也就不会填
  • 若是隐含字段带有较大的随机字符串变量, 则可能网络服务器会在表单提交时检查它们. 另外还有一些检查, 用来保证当前生成的表单变量只被使用一次或是最近生成的
  • html+css隐藏元素的方法:
    1. 经过简单css属性设置进行隐藏
    2. 隐含输入字段
    3. 设置元素的位置超出浏览器边界, 并隐藏滚动条
  • Selenium能够获取访问页面的内容, 所以它能够区分页面上的可见与不可见元素, 经过is_displayed()能够判断元素在页面上是否可见. 连第3种方式隐藏的元素都能被揪出来!
  • 在提交表单以前, 确认已经在表单中, 准备提交的隐含字段的值(或者让Selenium自动提交)

问题检查表

  • 首先,若是从网络服务器收到的页面是空白的,缺乏信息,或其遇到他不符合预期的状况(或者不是在浏览器上看到的内容),有多是由于网站建立页面的 JavaScript执行有问题
  • 若是准备向网站提交表单或发出 POST 请求,记得检查一下页面的内容,看看想提交的每一个字段是否是都已经填好,并且格式也正确。用 chrome 浏览器的网络面板(快捷键 f12 打开开发者控制台,而后点击“network”便可看到)查看发送到网站的 POST命令,确认每一个参数都是正确的。
  • 若是已经登陆网站却不能保持登陆状态,或者网站上出现了其余的“登陆状态”异常,请检查 cookie。确认在加载每一个页面时 cookie 都被正确调用,并且 cookie 在每次发起请求时都发送到了网站上。
  • 若是在客户端遇到了 HTTP 错误,尤为是 403 禁止访问错误,这可能说明网站已经把此 IP 看成机器人了,再也不接受任何请求。要么等待 IP 地址从网站黑名单里移除,要么就换个 IP 地址. 若是你肯定本身并无被封杀,那么再检查下面的内容。
  • 确认爬虫在网站上的速度不是特别快。快速采集是一种恶习,会对网管的服务器形成沉重的负担,还会让本身陷入违法境地,也是 IP 被网站列入黑名单的首要缘由。给爬虫增长延迟,让它们在夜深人静的时候运行。切记:匆匆忙忙写程序或收集数据都是拙劣项目管理的表现;应该提早作好计划,避免临阵慌乱
  • 还有一件必须作的事情:修改你的请求头!有些网站会封杀任何声称本身是爬虫的访问者。若是不肯定请求头的值怎样才算合适,就用浏览器的请求头
  • 确认没有点击或访问任何人类用户一般不能点击或接入的信息
  • 若是用了一大堆复杂的手段才接入网站,考虑联系一下网管吧,告诉他们目的。试试发邮件到 webmaster@< 域名 > 或 admin@< 域名 >,请求网管容许你使用爬虫采集数据。管理员也是人嘛!

用爬虫测试网站

  • 当研发一个技术栈较大的网络项目时,常常只对栈底(项目后期用的技术)进行一些常规测试.
  • 网站一般是不一样标记语言额编程语言的大杂烩. 这使网站的前端测试自动化变得困难. 好比, 为 JavaScript 部分写单元测试,但没什么用,若是 JavaScript 交互的 HTML 内容改变了,那么即便 JavaScript 能够正常地运行,也不能完成网页须要的动做

测试简介

  • 一个单元测试一般包含如下特色:
  • 每一个单元测试用于测试一个组件(component). 一般一个组件的全部单元测试都集成在同一个类里
  • 每一个单元测试均可以彻底独立地运行, 一个单元测试须要的全部启动(setup)和卸载(teardown)都必须经过这个单元测试自己去处理. 单元测试不能对其余测试形成干扰, 并且不管按何种顺序排列, 都必须可以正常运行
  • 每一个单元测试一般至少含有一个断言
  • 单元测试与生产代码是分离的. 虽然它们须要导入而后在待测试的代码中使用,可是它们通常被保留在独立的类和目录中。

python单元测试

  • python的单元测试模块unittest. 只要先导入模块而后继承unittest.TestCase类, 就可实现:
    1. 为每一个单元测试的开始和结束提供setUptearDown函数
    2. 提供不一样类型的断言
    3. 将全部以test_开头的函数看成单元测试运行, 忽略不带test_的函数
  • setUpClass函数只在类的初始化阶段运行一次, setUp函数在每一个测试启动时都运行.

Selenium单元测试

  • Selenium是一个能够解决网站上各类复杂问题的优秀测试框架, 初衷就是用来作网站测试
  • Selenium能够在浏览器上作任何事情, 包括输入, 点击等, 这样就能够找出异常表单, JavaScript 代码错误, html排版错误, 以及其余用户使用过程当中可能出现的问题
  • Selenium测试的关键是element. 能够对任何给定元素作许多操做, 如:
    1. myElement.click()
    2. myElement.click_and_hold()
    3. myElement.release()
    4. myElement.double_click()
    5. myElement.send_keys_to_element(“content to enter”()
  • 为了一次性完成一个元素的多个操做, 能够用行为连(action chain)储存多个操做, 而后在程序中执行屡次
  • .drag_and_drop实现拖拽, 可用于一部分登陆验证
  • driver.get_screenshot_as_file("xxx")截屏

Python单元测试与Selenium单元测试的选择

  • Python 的单元测试语法严谨冗长,更适合为大多数大型项目写测试
  • Selenium 的测试方式灵活且功能强大, 能够成为一些网站功能测试的首选
  • 用Selenium能够轻易获取网站的信息, 而单元测试能够评估信息是否知足测试条件, 两者组合是最佳搭档
  • 任何网站上能看到的内容均可以经过Python的单元测试和Selenium组合来测试

Chapter14 远程采集

  • 当你中止在本身的笔记本上运行python爬虫, 生活会变得更加轻松

为何要用远程服务器

  • 创建爬虫的第一原则是: 全部信息均可以伪造. 能够用非本人的邮箱发送邮件, 经过命令自动化鼠标行为
  • 阻止网站被采集的注意力主要集中在识别人类与机器人的行为差别上面

Tor代理服务器

  • 洋葱路由(The Onion Router)网络,是一种IP地址匿名手段。经过不一样服务器构成多个层(就像洋葱)把客户端包在最里面。数据进入网络以前会被加密,所以任何服务器都不能偷取通讯数据
  • 虽然 Tor 网络可让你访问网站时显示的 IP 地址是一个不能跟踪到你的 IP 地址,可是你在网站上留给服务器的任何信息都会暴露你的身份。
  • 登陆 Tor 网络不是一个自动的匿名措施,也不能让你进入互联网上任何区域。虽然它是一个实用的工具,可是用它的时候必定要谨慎、清醒,而且遵照道德规范
  • 当你用 Tor 的时候网速会变慢。这是由于代理有可能要先在全世界网络上转几回才到目的地!
  • tor服务必须运行在9150端口上
  • PySocks是一个代理服务器通讯模块, 可与tor配合使用
  • tor中使用seleniumphantomjs, 不须要pysocks, 只要保证tor在运行, 而后增长service_args参数设置代理端口, 让selenium经过端口9150链接网站就能够了

互联网其实就是一个用户界面不太友好的超级APIjavascript

The Zen of Python

Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren’t special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one– and preferably only one –obvious way to do it. Although that way may not be obvious at first unless you’re Dutch. Now is better than never. Although never is often better than right now. If the implementation is hard to explain, it’s a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea – let’s do more of those!php

优美胜于丑陋 明了胜于隐晦 简洁胜于复杂 复杂胜于混乱 扁平胜于嵌套 宽松胜于紧凑 可读性很重要 即使是特例,也不可违背这些规则 虽然现实每每不那么完美 可是不该该放过任何异常 除非你肯定须要如此 若是存在多种可能,不要猜想 确定有一种——一般也是惟一一种——最佳的解决方案 虽然这并不容易,由于你不是Python之父 1 动手比不动手要好 但不假思索就动手还不如不作 若是你的方案很难懂,那确定不是一个好方案 若是你的方案很好懂,那确定是一个好方案 命名空间很是有用,咱们应当多加利用css

互联网简介

  • 互联网是一种信息交换形式
  • 当http从浏览器收到一个数据包, 数据包的内容必定被当作一个网站, 网站的结构由html构成
  • 虽然html一般被当作是编程语言, 但它实际是一个标记语言, 经过标签订义文档等结构以肯定各个元素
  • css是配合html对网站样式进行定义的语言, 其为网站对象定义颜色, 位置, 尺寸和背景等属性

网络数据采集的法律和道德约束

  • 知识产权分3种基本类型: 商标(^TM或®), 版权(©), 专利.
  • 专利用来声明内容全部权仅属于发明者
  • 商标是一个单词, 词组, 符号或设计, 用来识别和区分一种商品的来源. 商标的全部权很大程度上由使用场景决定
  • 只要将一件东西带到世间, 它就自动受到版权法的保护
  • 版权保护只涉及创造性的做品, 不涉及统计数据或事实, 而许多爬虫采集的都是事实和统计数据. 若是数据是事实性的信息, 那么彻底照搬也不违反版权法
  • 若是知足下列条件, 爬虫算侵犯动产:
    1. 缺乏许可. 若是网站的服务协议条款明确禁止使用爬虫
    2. 形成实际伤害.
    3. 故意而为- -
  • 只有三个条件都知足, 才算侵犯动产.
  • 若是网速正常, 即便一台pc也能够给许多网站形成沉重负担.
  • 真的没理由去伤害别人的网站
  • 可能能够在大型网站的根目录找到robots.txt(我真的在维基百科上找到了!)
  • robots.txt 文件能够被程序轻易地解析和使用, rebots.txt 文件的语法没有标准格式。它是一种业内惯用的作法. rebots.txt 文件并非一个强制性约束.
  • robots.txt第一行非注释内容是 User-agent: ,注明具体哪些机器人须要遵照规则。后面是一组规则 Allow: 或 Disallow: ,决定是否容许机器人访问网站的该部份内容. 若是一条规则后面跟着一个与之矛盾的规则,则按后一条规则执行.
  • google爬虫采集网站时, 会为网站留一个副本, 而后放在互联网上, 任何人可接入这些缓存. http://webcache.googleusercontent.com/search?q=cache:YourURL
相关文章
相关标签/搜索