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. 安装win8+Ubuntu14.04双系统的经验总结

    当时查资料,很多人推荐了easyBCD直接安装ubuntu,但是在我的笔记本上行不通.我的笔记本是Lenovo V480+win8正版系统.这是因为我的笔记本的引导结构是EFI,而不是MBR.我的方法 ...

  2. TypeScript笔记 4--变量声明

    在上一篇:基础变量中我们在声明变量时使用了关键字let,这和JS中的var有点类似. 语法 基本语法:let 变量名:类型.当然类型不是必须的. let x:number; let y:string ...

  3. HDU 1979 Red and Black

    题目: There is a rectangular room, covered with square tiles. Each tile is colored either red or black ...

  4. 阻止安卓实体返回键后退的网页js实现

    提供两种解决方法吧,都是网上来的,侵权删,毕竟我等只是搞后端的-- 第一种方法: // 阻止安卓实体键后退 // 页面载入时使用pushState插入一条历史记录 history.pushState( ...

  5. VS的无用文件

    目录:C:\ProgramData\Microsoft Visual Studio\10.0\TraceDebugging 每次调试程序都会产生30MB左右大小的Debug文件.如何禁止? Tools ...

  6. 《You dont know JS》类型篇总结

    类型 javaScript中的类型和熟知的一些强类型语言的有关类型的定义是不一样的.在js中,类型的含义是值的内部特征,它定义了值得行为,以使其区别于其他值.(a type is an intrins ...

  7. vue2.0集成百度UE编辑器,上传图片报错!!!

    我这边配置进去之后,界面加载,文本输入都没有问题,就是上传图片会有问题 这张图, 左边红色框框 就是目录结构咯, 右边红色框框 就是各种网上教程给出的第一个路径配置对吧, 下面的就是绿色 服务器接口配 ...

  8. centos利用yum安装卸载软件常用命令

    来自:http://tech.v01.cn/Linuxchangjianwenti/changyongruanjiananzhuangyucao/2012/0119/70.html 一.使用yum安装 ...

  9. shell 实现主板测试

    初接触shell,只能需要用到什么功能现学先用了.本文总结一下完成测试程序当中遇到的技巧和问题. 01. 变量生存期的问题,在函数中的变量无法在其他地方使用,在函数中只能使用在函数前定义的全局变量: ...

  10. 图像插值:OpenCV_remap

    此为opencv中remap函数移植和分析,整理了双线性的插值部分的代码尚未完全移植,但最困难的部分已经完成,而恰巧在这时,发现其实现并不是那么的令我满意,于是终止,改为自己实现.考虑到以后可能会用到 ...