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

作者: 2MuchT | 来源:发表于2017-06-26 13:39 被阅读210次

    介绍

    一直想有时间学习爬虫技术,现在来吧,跟着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())
    
    逆时针箭头顺序

    正则表达

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

    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

        本文链接:https://www.haomeiwen.com/subject/fotefxtx.html