You Don't Always Need a Hammer

When Michelangelo was asked how he could sculpt a work of art as masterful as his David, he is famously reported to have said: “It is easy. You just chip away the stone that doesn’t look like David.”

这里将Web Scraping比作雕刻,即“用锤子去掉那些不像‘David’的部分”,在解析难题(Gordian Knot)的时候(即此网站很难去爬),我们不总是需要“锤子”(即我们不要一开始就dive),我们需要做的更聪明点:

  • 查看此网页有无 print this page,或者移动端版本的html(通常来说移动端的html格式和架构会更好些)
  • 查看JavaScript File有无自己想要的信息
  • 也许URL就有你想要的信息
  • 有无其它比较好爬的网页同样能得到你的信息

Another Serving of BeautifulSoup

几乎每个网站都会有层叠样式表(Cascading Style Sheet, CSS)。CSS 可以让 HTML 元素呈现出差异化,使那些具有完全相同修饰的元素呈现出不同的样式。

比如一些标签看起来是这样:

我们可以通过创建一个这样的网络爬虫来爬取网页中的所有人物名称(此网页中人物名字都是绿色的):

from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/warandpeace.html")
bsObj = BeautifulSoup(html)
nameList = bsObj.findAll("span", {"class":"green"})
for name in nameList:
    print(name.get_text())
    

关于get_text()函数

get_text() 会把你正在处理的 HTML 文档中所有的标签都清除,然后返回一个只包含文字的字符串。 假如你正在处理一个包含许多超链接、段落和标签的大段源代码, 那么 .get_text() 会把这些超链接、段落和标签都清除掉,

只剩下一串不带标签的文字。

例如,上面的代码的结果是(只保留了前五行):

Anna
Pavlovna Scherer
Empress Marya
Fedorovna
Prince Vasili Kuragin

如果print(name.get_text())换成 print(name),运行结果就会变成:

<span class="green">Anna
Pavlovna Scherer</span>
<span class="green">Empress Marya
Fedorovna</span>
<span class="green">Prince Vasili Kuragin</span>

关于BeautifulSoup中的findAll函数和find函数

BeatifulSoup文档中两者的定义是:

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

find 其实等价于findAll的limit等于1时的情形。如果你只对网页中获取的前 x 项结果感兴趣,就可以设置它。

find和findAll函数中关键词参数的注意事项

虽然bsObj.findAll(id="text")bsObj.findAll("", {"id":"text"})是完全一样的,但是偶尔会出现问题,比如我们用class属性查找标签,如果这样写代码:bsObj.findAll(class="green"),就会

因为class是python中的保留字而产生一个语法错误。一个比较臃肿的解决方案是在class后增加一个下划线:bsObj.findAll(class_="green"),或者:bsObj.findAll("", {"class":"green"})

Other BeautifulSoup Objects

NavigableString Object

用来表示标签里的文字,不是标签。

Comment Object

Used to find HTML comments in comment tags,

再加上我们之前学习的Tag ObjectBeautifulSoup对象,这四个对象就是我们用BeautifulSoup库时能遇到的所有对象了,

Navigating Trees

一个html页面可以被映射成一棵树,以http://www.pythonscraping.com/pages/page3.html 为例,Navigating Tree是:

html
— body
— div.wrapper
— h1
— div.content
— table#giftList
— tr
— th
— th
— th
— th
— tr.gift#gift1
— td
— td
— span.excitingNote
— td
— td
— img
— ……其他表格行省略了……
— div.footer

children和descendants

我们在处理标签时,可以选择处理它的children或是descendants,但这里有一个极其容易混淆的地方,以以下代码为例:

from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
for child in bsObj.find("table",{"id":"giftList"}):
print(child)

上面的代码打印了bsObj的后代中所有符合条件的标签。在上面代码的第5行加上.children()和不加上是一样的,即for child in bsObj.find("table",{"id":"giftList"}):

for child in bsObj.find("table",{"id":"giftList"}).children:等价。

而处理descenents,是处理完后代之后继续遍历一遍它的后代标签并得到标签的text,例如上面(children)代码得到的结果(一部分)是:

<tr><th>
Item Title
</th><th>
Description
</th><th>
Cost
</th><th>
Image
</th></tr>

如果将代码的for child in bsObj.find("table",{"id":"giftList"}):换成for child in bsObj.find("table",{"id":"giftList"}).descendants:,结果(一部分)会变成:

<tr><th>
Item Title
</th><th>
Description
</th><th>
Cost
</th><th>
Image
</th></tr>
<th>
Item Title
</th>

Item Title

<th>
Description
</th>

Description

<th>
Cost
</th>

Cost

<th>
Image
</th>

Image

通过上面结果我们可以得知,descendant在访问后代标签之后,又循环遍历了一遍后代标签,并且输出了text信息。

siblings

from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
for sibling in bsObj.find("table",{"id":"giftList"}).tr.next_siblings:
print(sibling)

这行代码会打印产品列表的所有行的产品,但是不会打印标题,原因是自己不能被视为自己的兄弟。

Make Selections Specifc

切记不要直接使用标签来得到你想要的信息,比如:bsObj.table.tr虽然和bsObj.find("table",{"id":"giftList"}).tr得到的结果一样,但是后者更稳定。

parents

from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
print(bsObj.find("img",{"src":"../img/gifts/img1.jpg"
}).parent.previous_sibling.get_text())

原标签结构为:







— (3)

— “$15.00” (4)

— s (2)

— <img src=”../img/gifts/img1.jpg">(1)

结果为:$15.00

Regular Expressions

正则表达式,简称为regex,大二《编译原理》课有很详细的学过这方面的知识,就不再赘述了。

Regular Expressions and BeautifulSoup

同时运用两方面的知识来构建一个爬虫,regex可以让我们得到的信息更具体,在一些需要对信息进行限制的情况下我们需要用到regex。

Accessing Attributes

myTag.attrs这样的格式可以获取标签的所有属性。

Lambda Expressions

Lambda表达式,或许可以用来替代regex,不展开说。

Beyond BeautifulSoup

介绍了除BeautifulSoup之外可以用到的库,但目前我打算专注BeautifulSoup,就不去了解了。

  • lxml

  • HTML Parser

《Web Scraping With Python》Chapter 2的学习笔记的更多相关文章

  1. <Web Scraping with Python>:Chapter 1 & 2

    <Web Scraping with Python> Chapter 1 & 2: Your First Web Scraper & Advanced HTML Parsi ...

  2. Web Scraping with Python读书笔记及思考

    Web Scraping with Python读书笔记 标签(空格分隔): web scraping ,python 做数据抓取一定一定要明确:抓取\解析数据不是目的,目的是对数据的利用 一般的数据 ...

  3. Web scraping with Python (part II) « Jean, aka Sig(gg)

    Web scraping with Python (part II) « Jean, aka Sig(gg) Web scraping with Python (part II)

  4. 阅读OReilly.Web.Scraping.with.Python.2015.6笔记---Crawl

    阅读OReilly.Web.Scraping.with.Python.2015.6笔记---Crawl 1.函数调用它自身,这样就形成了一个循环,一环套一环: from urllib.request ...

  5. 阅读OReilly.Web.Scraping.with.Python.2015.6笔记---找出网页中所有的href

    阅读OReilly.Web.Scraping.with.Python.2015.6笔记---找出网页中所有的href 1.查找以<a>开头的所有文本,然后判断href是否在<a> ...

  6. 阅读OReilly.Web.Scraping.with.Python.2015.6笔记---BeautifulSoup---findAll

    阅读OReilly.Web.Scraping.with.Python.2015.6笔记---BeautifulSoup---findAll 1..BeautifulSoup库的使用 Beautiful ...

  7. 首部讲Python爬虫电子书 Web Scraping with Python

    首部python爬虫的电子书2015.6pdf<web scraping with python> http://pan.baidu.com/s/1jGL625g 可直接下载 waterm ...

  8. $《利用Python进行数据分析》学习笔记系列——IPython

    本文主要介绍IPython这样一个交互工具的基本用法. 1. 简介 IPython是<利用Python进行数据分析>一书中主要用到的Python开发环境,简单来说是对原生python交互环 ...

  9. Web Scraping with Python

    Python爬虫视频教程零基础小白到scrapy爬虫高手-轻松入门 https://item.taobao.com/item.htm?spm=a1z38n.10677092.0.0.482434a6E ...

随机推荐

  1. css3渐变之线性渐变

    css3定义了两种类型的渐变,即线性渐变和径向渐变.这里我要说的是线性渐变. 为了创建一个线性渐变,你必须至少定义两种颜色结点.颜色结点即你想要呈现平稳过渡的颜色.同时,你也可以设置一个起点和一个方向 ...

  2. line-height相关总结

    line-height http://cindylu520.iteye.com/blog/670512 四个boxes containing boxes inline boxes 匿名inline b ...

  3. DEDECMS去掉自动生成首页或栏目后面带的index.html

    Dede默认生成首页后,首页的链接后面会多出一个index.html.据官方说法这样有利于网站优化.但是这个index.html怎么看都不舒服,而且也不利于seo中主页url的统一.因为我的网站的ur ...

  4. php 5.0 与7.0有什么区别

    我有更好的答案 发布于2017-05-19 12:30 最佳答案 PHP7特性 PHP 7.0.0 Alpha 1[1] 使用新版的ZendEngine引擎,带来了许多新的特性,以下是不完全列表: 性 ...

  5. shareInstance

    2.+(id)shareInstance; 外界初始化得到单例类对象的唯一借口,这个类方法返回的就是instance,即类的一个对象, 如果instance为空,则实例化一个对象,如果不为空,则直接返 ...

  6. web前端学习(2):开始编写HTML

    在第一章中,我们初步了解了上网的过程,同时也明白了所谓网页,其本质就是主要用HTML语言所写的一份文档.相信大多数人在了解HTML文件前,最先接触的是利用"记事本"所写的文档或者是 ...

  7. angular4 中自定义pagination组件

    你用Angular 吗? 一.介绍 一个基于angular4 开发的可以分页的组件.组件的好处就是可以复用,复用.....作为一个前端码农,开始的分页功能实现是我用jquery写的,其他同事用的时候都 ...

  8. Django之modelform组件

    一.简介与基本使用 简介:django中的modelform组件同时具有model和form作用,但是耦合度比较高,当项目需要拆分时候就比较困难了,所以在使用modelform时候需要先考虑项目的扩展 ...

  9. springmvc +mybatis 配置多数据源

    1.数据源配置: jdbc_multiple.properties: # MySQL #======================================================== ...

  10. flask_route错误:AttributeError: 'function' object has no attribute 'route'

    问题: 路由完全正确,当只有一个名为home的函数处理这个路由时候,下一个路由处理函数,总是提示没有这个rotue属性 Traceback (most recent call last): File ...