爬虫笔记-01-爬虫介绍和BeautifulSoup

介绍

一直想有时间学习爬虫技术,现在来吧,跟着OReilly 出版的Web Scraping with Python 这本书来学习。

环境准备

因为本书推荐Python3为例,去官网下载Python3.x版本的Python安装包,直接安装就好了。安装的时候注意勾选加入path

话说我还没有学Python呢亲( ⊙ o ⊙ )!,没关系先稀里糊涂的用吧~~~ 不行了再说

第一只爬虫

书中首先做了一些介绍,主要内容是网络传输的过程,说白了就是web交互其实可以跟浏览器没有啥关系,而爬虫就是不通过浏览器从服务端去爬数据...

初见

ok闲言碎语不要讲来写爬虫吧
新建一个文件夹,里面建一个test.py文件,在里面写入:

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

据说Python是一个很矫情的对空格、缩进敏感的语言..所以一定要注意不要乱打空格和缩进
保存,然后命令行cd到这个文件的目录:

phython test.py

可以看到打印出来的html

美丽的汤

BeautifulSoup是一个lib,用来更好的解析html和xml的。

安装汤

python3自带了pip所以可以直接用pip安装

pip install beautifulsoup4

Virtual Environments是一个隔离各个项目lib防止冲突的机制,由于我初学,先不用

安装完bs4之后试一下:

from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.pythonscraping.com/pages/page1.html")
bsObj = BeautifulSoup(html.read())
print(bsObj.h1)

直接使用bsObj.h1找到了html中的h1标签里的内容。这是比较暴力的写法,比较精确的写法是bsObj.html.body.h1

异常处理

异常处理可以使程序更健壮,不容易直接挂掉。看下面的写法:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup

def getTitle(url):
    try:
        html = urlopen(url)
    except HTTPError as e:
        return None
    try:
        bsObj = BeautifulSoup(html.read())
        title = bsObj.body.h1
    except AttributeError as e:
        return None
    return title
title = getTitle("http://www.pythonscraping.com/pages/page1.html")
if title == None:
    print("Title could not be found")
else:
    print(title)

以上方法才是比较正规健壮的写法,一定要注意格式,不然会报错的,不行就装个IDE 比如Pycharm,如果格式不正确会有提示。

高级HTML解析

从一个复杂的页面提取到需要的信息可能需要深层的抓取比如:
bsObj.findAll("table")[4].findAll("tr")[2].find("td").findAll("div")[1].find("a")
这样的代码很可怕也很脆弱,当页面出现改动后,这个路径就抓不到信息了。
有什么解决方案?

  • 通过手机版或打印预览,来获取更规范的HTML
  • 解析网页引用的js文件
  • 通过网页URL获取信息
  • 从其他类似的网站获取信息

书上说的以上方法很湿,一点都不干货...

BeautifulSoup 的其功能

使用属性、导航树、搜索标签
网页的样式表 也可以用来查找信息

看例子,这个网页,有red和green的文字:
http://www.pythonscraping.com/pages/warandpeace.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())

以上,使用bsObj.findAll(tagName, tagAttributes)查询返回列表

find()和findAll()的用法

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

查找多个类型的标题:

.findAll({"h1","h2","h3","h4","h5","h6"})

查找多个属性:

.findAll("span", {"class":"green", "class":"red"})

递归

findAll()方法的递归属性默认是true,意味着查找所有子节点。

以内容为条件查询标签:

nameList = bsObj.findAll(text="the prince")
print(len(nameList))

limit

limit是限制查找的个数,比如只返回前10个符合条件的标签

keywords

有点复杂 先不看

Navigation Trees

Navigation Tree就类似这种用法:
bsObj.tag.subTag.anotherSubTag

一个用来做例子的页面:
http://www.pythonscraping.com/pages/page3.html

处理子节点和后代节点

在BeautifulSoup里面 子节点child和“”孙子及后代“descendants 是被两个概念。两个范围没有交集。
注意bsObj.body.h1这个代码返回的不一定是 body-h1,而有可能是body-........h1。
如果只想得到儿子则使用:bsObj.find("table",{"id":"giftList"}).children这种方式。

处理sibling兄弟姐妹

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)

打印出了所有的产品内容,出了第一行title。原因:

  • sibling(兄弟)不包括自己
  • next_siblings只返回next的,而不是它和它之前的,如果object本身在在队列中间,那么只返回它后面的兄弟

同理如果需要返回前面的兄弟可以使用previous_siblings

以上两周可以理解为,返回哥哥、返回弟弟
另外,去掉siblings后面的s 可以只返回一个靠的最近的兄弟。

处理爹妈,父标签(这标题...)

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())
爬虫笔记-01-爬虫介绍和BeautifulSoup_第1张图片
爬虫笔记-01-爬虫介绍和BeautifulSoup_第2张图片
逆时针箭头顺序

正则表达

正则表达式....呃 头大

As the old computer-science joke goes: “Let’s say you have a problem, and you decide
to solve it with regular expressions. Well, now you have two problems.”

爬虫技术脱不了使用正则表达式

上面的例子使用的是准确的src来找到特指的img,但是如果要找很多的img就要使用正则了:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import re

html = urlopen("http://www.pythonscraping.com/pages/page3.html")
bsObj = BeautifulSoup(html)
images = bsObj.findAll("img", {"src":re.compile("\.\.\/img\/gifts/img.*\.jpg")})
for image in images:
    print(image["src"])

获取属性

myImgTag.attrs['src']

Lambda表达式

将一个方法作为变量传递到另一个方法中,但是方法的参数必须是一个tag返回一个boolean
例子:
soup.findAll(lambda tag: len(tag.attrs) == 2)
返回有两个属性的标签
这可能是替代正则表达式的一种方法

你可能感兴趣的:(爬虫笔记-01-爬虫介绍和BeautifulSoup)