爬虫学习(01)

爬虫第一步:获取页面

一、信息在网络连接层的传递

(Bob 从Alice那里获得信息)

  1. Bob的电脑发送一个字节流,由信息组成,包含header和body。header包含一个本地路由器MAC地址的直接目的地,和Alice的IP地址的最终目的地。body包含他对接受Alice服务器应用程序的请求。
  2. Bob的本地路由器接收所有这些1和0,并将它们解释为一个包,来自Bob自己的MAC地址,目的地是Alice的IP地址。他的路由器把自己的IP地址作为“来自”IP地址印在包上,然后通过互联网发送出去。
  3. Bob的包穿过几个中间服务器,这些服务器将他的包指向Alice服务器上正确的物理/有线路径。
  4. Alice的服务器在她的IP地址接收数据包。
  5. Alice的服务器读取报头中的包端口目的地,并将其传递给适当的应用程序——web服务器应用程序。(对于web应用程序,包端口目的地几乎总是端口80;这可以看作是包数据的公寓号,而IP地址就像街道地址一样。)
  6. eb服务器应用程序从服务器处理器接收数据流。这些数据说明了如下内容:
  • 这是一个GET请求。
  • 请求以下文件:index.html。
  1. web服务器定位正确的HTML文件,将其打包成一个新的包发送给Bob,并将其发送到本地路由器,以便通过相同的过程将其传输回Bob的机器。

二、python 虚拟环境

如果您打算处理多个Python项目,或者您需要一种方法来轻松地将项目与所有关联的库捆绑在一起,或者您担心已安装的库之间可能存在冲突,那么您可以安装一个Python虚拟环境来保持所有内容分离并易于管理。

    $ virtualenv scrapingEnv

创建一个环境scrapingEnv,产生了一个单独的文件夹,包含一套独立的python运行环境,安装的任何库或运行的脚本都将只在该虚拟环境下运行。运行虚拟环境:

    $ cd scrapingEnv/
    $ source bin/activate
    (scrapingEnv)ryan$ pip install beautifulsoup4
    (scrapingEnv)ryan$ python
    > from bs4 import BeautifulSoup
    >
    (scrapingEnv)ryan$ deactivate

    ryan$ python
    > from bs4 import BeautifulSoup
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>

三、urllib.request.urlopen 从一个网络地址获取html文件

from urllib.request import urlopen
html = urlopen('http://pythonscraping.com/pages/page1.html')
print(html.read())

urllib是一个标准的Python库(意味着您不需要安装任何额外的程序来运行这个示例),它包含用于跨web请求数据、处理cookie、甚至更改元数据(如标题和用户代理)的函数。

urlopen用于跨网络打开远程对象并读取它。它是一个相当通用的函数(它可以轻松地读取HTML文件、图像文件或任何其他文件流)

四、BeautifulSoup 处理html页面

BeautifulSoup 通过修复糟糕的HTML和向我们提供表示XML结构的易于遍历的Python对象来帮助格式化和组织混乱的web。

安装:

    $sudo  apt-get install python-bs4
    or:
    $pip install beautifulsoup4

运行:

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen('http://www.pythonscraping.com/pages/page1.html')
bs = BeautifulSoup(html.read(), 'html.parser')  # 无需.read()
print(bs.h1)
----------------------Output--------------------------
<h1>An Interesting Title</h1>

bs = BeautifulSoup(html.read(), 'html.parser')将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>Loremip...</div></body>
        h1 → <h1>An Interesting Title</h1>
        div → <div>Lorem Ipsum dolor...</div>

然后可以访问不同层次结构:比如获得h1 tag:
bs.h1;bs.html.h1;bs.body.h1;bs.html.body.h1都可以

其中参数'html.parser'表示将其以html良好结构进行解析,无需安装直接使用。其他还有'lxml'和'html5lib'两者都是解析方式,不过都需要先下载安装pip install lxmlpip install html5lib.
lxml格式可以处理更糟糕的html代码,可以进行修复,而且比html.parser更快。缺点在于需要安装,依赖于第三方C库,可能出现易使用型和移植性问题。html5lib是一个非常宽容的解析器,它甚至可以主动更正损坏的HTML。它还依赖于外部依赖,并且比lxml和html.parser都要慢。

五、可靠地连接并处理异常

获取页面出错

  1. 服务器上找不到页面 HTMLError
  2. 找不到服务器 URLError
from urllib.request import urlopen
from urllib.error import HTTPError
from urllib.error import URLError

try:
    html_1 = urlopen('http://www.pythonscraping.com/pages/pagenofound.html')
    html_2 = urlopen('https://pythonscrapingthisurldoesnotexist.com')
except HTTPError as e:
    print(e)
except URLError as e:
    print('The server could not be found!')
else:
    print('It Worked!')

tag获取出错

如果从服务器成功检索到页面,仍然存在页面上的内容与预期不完全一致的问题。每次在BeautifulSoup对象中访问标记时,明智的做法是添加一个检查来确保标记确实存在。如果您试图访问一个不存在的标记,BeautifulSoup将返回一个None对象。如果要继续访问深层tag,则出现None对象的AttributeError错误。

try:
    badContent = bs.nonExistingTag.anotherTag
except AttributeError as e:
    print('Tag was not found')
else:
    if badContent == None:
        print ('Tag was not found')
    else:
        print(badContent)

爬虫第二步:HTML 解析和信息提取

注意:一般不要去通过使用多行语句层层深入来找到所要的信息。可能因为页面的变化而出错

bs.find_all('table')[4].find_all('tr')[2].find('td').find_all('div')[1].find('a')

接下来的beautifulsoup对象的信息提取都建立在获取页面内容之后:

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen('http://www.pythonscraping.com/pages/page1.html')
bs = BeautifulSoup(html.read(), 'html.parser')

一、通过属性匹配获得特定tag

nameList = bs.findAll('span', {'class':'green'})
for name in nameList:
    print(name.get_text())
  1. bs.find_all(tagName, tagAttributes)来获取页面上所有标记的列表,而不仅仅是第一个标记。
  2. tagName.get_text(),以便将内容从标记中分离出来。

find() 和 find_all()

BeautifulSoup的find()和find_all()是您可能最常用的两个函数。有了它们,您可以很容易地过滤HTML页面,根据它们的各种属性找到所需标记的列表,或者单个标记。

find_all(tag, attributes, recursive, text, limit, keywords)
find(tag, attributes, recursive, text, keywords)

tag: 可以传递标记的字符串名称,甚至Python字符串标记名称列表

.find_all(['h1','h2','h3','h4','h5','h6'])

attributes:获取属性的Python字典,并匹配包含这些属性之一的标记

.find_all('span', {'class':{'green', 'red'}})

recursive:布尔值。您希望文档深入到什么程度?如果recursive被设置为True, find_all函数将查找与参数匹配的标记的子标记和子标记的子标记。如果它是假的,它将只查看文档中的顶级标记。默认情况下,find_all递归工作(recursive设置为True)

text:根据标记的文本内容进行匹配,而不是根据标记本身的属性进行匹配

nameList = bs.find_all(text='the prince')
print(len(nameList))

keywords:允许您选择包含特定属性或属性集的标记

title = bs.find_all(id='title', class_='text')

但keywords可以用attributes参数替代:

bs.find_all('', {'id':'text','class':'text'})

二、通过html组织结构获取tag

children and descendants 直接子代和所有后辈

在BeautifulSoup库和许多其他库中,在子库和后代库之间有一个区别:就像在人类族谱中一样,子库总是恰好比父库低一个标记,而后代库可以在父库下面的树中的任何级别。
一般来说,BeautifulSoup函数总是处理选中的当前标记的后代。例如,bs.body.h1选择第一个h1标记,它是body标记的后代。它不会找到位于主体外部的标记。类似地,bs.div.find_all('img')将在文档中找到第一个div标记,然后检索该div标记的后代的所有img标记的列表.
如果您希望只找到子代,可以使用.children标记

for child in bs.find('table',{'id':'giftList'}).children:
    print(child)

所有后辈则使用.descendants

for all_child in bs.find('table',{'id':'giftList'}).descendants:
    print(all_child)

siblings同层次兄弟姐妹

for sibling in bs.find('table',{'id':'giftList'}).tr.next_siblings:
    print(sibling)

当你得到一个对象的兄弟siblings对象时,该对象本身将不会包含在列表中。正如函数名所暗示的,它只调用下面同层次的所有兄弟姐妹。例如,如果在列表中间选择一行,并对其调用next_siblings,则只返回后续的兄弟姐妹。因此,通过选择标题行并调用next_siblings,可以选择表中的所有行.

作为对next_siblings的补充,previous_siblings函数通常很有用,如果您希望得到的同胞标记列表的末尾有一个易于选择的标记。previous_siblings返回同层次的所有兄弟姐妹

也有next_sibling和previous_sibling函数,它们执行的函数几乎与next_sibling和previous_sibling相同,只不过它们返回的是单个标记,而不是它们的列表

parent 父代标记

bs.find('img',{'src':'../img/gifts/img1.jpg'}).parent.previous_sibling.get_text()

三、正则表达式

import re

images = bs.find_all('img',
    {'src':re.compile('\.\.\/img\/gifts/img.*\.jpg')})
for image in images:
    print(image['src'])

只打印以../img/gifts/img开头并且以.jpg结尾的相对图像路径。 输出结果如下:

../img/gifts/img1.jpg
../img/gifts/img2.jpg
../img/gifts/img3.jpg
../img/gifts/img4.jpg
../img/gifts/img6.jpg

四、获取属性

使用标记对象,Python属性列表可以通过调用以下命令自动访问:
myTag.attrs
这实际上返回了Python dictionary对象,可以使用以下行找到图像的源位置:
myTag.attrs['src']

五、Lambda 表达式

BeautifulSoup允许您将某些类型的函数作为参数传递到find_all函数中。
唯一的限制是这些函数必须以标记对象作为参数并返回布尔值。beautifulsoup遇到的每个标记对象都在这个函数中求值,值为True的标记将被返回,其余的将被丢弃。
bs.find_all(lambda tag: len(tag.attrs) == 2)返回所有具有两个属性的标记

Lambda函数非常有用,您甚至可以使用它们来替换现有的BeautifulSoup函数
bs.find_all(lambda tag: tag.get_text() =='Or maybe he\'s only resting?')
等同于:
bs.find_all('', text='Or maybe he\'s only resting?')

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343