zoukankan      html  css  js  c++  java
  • 爬虫模块之解析模块

    一 BeautifulSoup4模块

     下载解释器:lxml,处理速度快,以下也是安装lxml解释器的。

    $ apt-get install Python-lxml
    $ easy_install lxml
    $ pip install lxml
    

     另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:

     $ apt-get install Python-html5lib
    $ easy_install html5lib
    $ pip install html5lib
    

    安装BeautifulSoup:pip install beautifulsoup4

     基本使用:

      prettify:处理好缩进,结构化显示

    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b></p>
    
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    #pip3 Beautifulsoup
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    # soup=BeautifulSoup(open('a.html',encoding='utf-8'),'lxml')
    
    print(soup.prettify())
    View Code

      遍历文档树:就是按照标签查找内容,直接对象.(点)标签。

      对象.(点)标签.(点)name:获取标签名

      attrs:获取属性

      string:获取文本内容,如果有多个文本,就会为None,因为不能定到唯一的一个。

      strings:获取文本信息,以一个生成器的格式返回所有的文本信息。

      atripped_strings:去掉空行,只保留文本内容。

      .(点):嵌套查找,从前面的所有标签找到第一个标签。

      contents:查找子节点

      children:查找到所有的子节点返回一个迭代器

      descendants:查找到所有的后代节点,返回的是一个生成器

      parent:父节点

      parents:所有的祖先节点

      next_sibling:,查找到下一个兄弟标签

      next_siblings:查到到下面的所有兄弟标签

      paevious_sibling:查找到上一个兄弟标签

      paevious_siblings:查找到上面的所有的兄弟标签

    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title"><b>The Dormouse's story</b>
    111111
    </p>
    
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    #遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个
    #1、用法
    # print(soup.a,type(soup.a))
    # #2、获取标签的名称
    # print(soup.a.name)
    # #3、获取标签的属性
    # print(soup.a.attrs)
    # #4、获取标签的内容
    # print(soup.a.string)
    # print(soup.p.string)
    # print(list(soup.p.strings))
    # print(list(soup.p.strings))
    # for line in soup.stripped_strings:
    #     print(line)
    
    
    #5、嵌套选择
    # print(soup.p.b.string)
    
    #6、子节点、子孙节点
    # print(soup.p.contents)
    # print(soup.p.children)
    #
    # print(soup.body.descendants)
    #7、父节点、祖先节点
    # print(soup.a.parent)
    # print(soup.a.parents)
    
    #8、兄弟节点
    # print(soup.a.next_sibling)
    # print(soup.a.previous_sibling)
    
    
    print(list(soup.a.next_siblings))
    print(list(soup.a.previous_siblings))
    View Code

     搜索文档数:

      过滤器:find和find_all

      find:只查找到第一个符合要求的节点

      find_all:查找到所有符合要求的要求的节点

       完全匹配:直接写入查找的条件

       正则匹配:compile(正则表达式)

       name:按照标签名查找。

       class_:按照类名查找 

       id:以id进行查找

      关键字=[.....]:列表过滤器,只要有[ ]里的内容,就会查找出来

      关键字=True:True过滤器,只要有这个属性就会查找出来

      has_attr('属性'):方法选择器,判断前面的内容是否存在后面的属性。

      key=value,逗号可以多个关键字

      attrs={’属性‘:“属性值”}:属性查找

      calss=“属性值1  属性值2”:完全匹配

      text:文本信息

      limit:留下几个查找的内容。

      recursive:是否让你递归的查找,False:否;True:是

    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title" id="ppp"><b>The Dormouse's story</b>
    111111
    </p>
    
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    # 1、字符过滤器:完全匹配
    # name=字符:与标签名完全匹配
    # id=字符:与id名完全匹配
    # print(soup.find_all('body'))
    # print(soup.find_all(name='body'))
    # print(soup.find_all(id='link'))
    
    # 2、正则过滤器
    import re
    # print(soup.find_all(name=re.compile('^b')))
    # print(soup.find_all(class_=re.compile('^st')))
    
    # 3、列表过滤器:符合列表中的一个条件即可
    # print(soup.find_all(id=['ppp','link1']))
    # print(soup.find_all(name=['a','b']))
    
    # 4、True
    # print(soup.find_all(id=True))
    # print(soup.find_all(name=True))
    
    # for tag in soup.find_all(True):
    #     print(tag.name)
    
    
    # 5、方法过滤器
    # tag.has_attr('class')
    # tag.has_attr('id')
    
    # def has_class_not_id(tag):
    #     return tag.has_attr('class') and not tag.has_attr('id')
    #
    # print(soup.find_all(has_class_not_id))
    
    
    
    
    #详细用法:find_all( name , attrs , recursive , text , **kwargs )
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title" id="ppp"><b class="sister">The Dormouse's story</b>
    111111
    </p>
    
    <p class="story">Once upon a time there were three little sisters; and their names were
    <a href="http://example.com/elsie" class="sister sss" id="link1">Elsie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
    and they lived at the bottom of a well.</p>
    
    <p class="story">...</p>
    """
    import re
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    #name:
    # print(soup.find_all(name='a'))
    # print(soup.find_all(name=re.compile('^b')))
    # print(soup.find_all(name=['a','b']))
    # print(soup.find_all(name=True))
    
    #keyword:key=value,
    # print(soup.find_all(id='link1'))
    # print(soup.find_all(class_='sister',href=re.compile('lacie')))
    # print(soup.find_all(class_='sister',href=re.compile('lacie'))[0].name)
    # print(soup.find_all(class_='sister',href=re.compile('lacie'))[0].attrs['href'])
    # print(soup.find_all(class_='sister',href=re.compile('lacie'))[0].string)
    
    # data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
    
    # print(data_soup.find_all(data-foo="value"))
    # print(data_soup.find_all(attrs={'data-foo':"value"}))
    
    
    #class_
    # print(soup.find_all(class_='sister sss'))
    # print(soup.find_all(class_='sss sister'))
    # print(soup.find_all(class_='sss'))
    
    #attrs
    # print(soup.find_all(name='a',attrs={'class':'sister'}))
    
    #text
    # print(soup.find_all(name='a',text='Tillie'))
    # print(soup.find_all(name='b',text=re.compile('y$')))
    
    #limit
    # print(soup.find_all(name='a',limit=2))
    
    #recursive
    # print(soup.find_all(name='body')[0].find_all(name='a',recursive=False))
    # print(soup.find_all(name='body')[0].find_all(name='p',recursive=False))
    
    
    # print(soup.find_all('a', limit=1))
    #
    # print(soup.find('a'))
    
    print(soup.head.title)
    print(soup.find('head').find('title'))
    View Code
    #3、find( name , attrs , recursive , text , **kwargs )
    find_all() 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个<body>标签,那么使用 find_all() 方法来查找<body>标签就不太合适, 使用 find_all 方法并设置 limit=1 参数不如直接使用 find() 方法.下面两行代码是等价的:
    
    soup.find_all('title', limit=1)
    # [<title>The Dormouse's story</title>]
    soup.find('title')
    # <title>The Dormouse's story</title>
    
    唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.
    find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .
    print(soup.find("nosuchtag"))
    # None
    
    soup.head.title 是 tag的名字 方法的简写.这个简写的原理就是多次调用当前tag的 find() 方法:
    
    soup.head.title
    # <title>The Dormouse's story</title>
    soup.find("head").find("title")
    # <title>The Dormouse's story</title>
    View Code
    #2、find_all( name , attrs , recursive , text , **kwargs )
    #2.1、name: 搜索name参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True .
    print(soup.find_all(name=re.compile('^t')))
    
    #2.2、keyword: key=value的形式,value可以是过滤器:字符串 , 正则表达式 , 列表, True .
    print(soup.find_all(id=re.compile('my')))
    print(soup.find_all(href=re.compile('lacie'),id=re.compile('d'))) #注意类要用class_
    print(soup.find_all(id=True)) #查找有id属性的标签
    
    # 有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
    data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
    # data_soup.find_all(data-foo="value") #报错:SyntaxError: keyword can't be an expression
    # 但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
    print(data_soup.find_all(attrs={"data-foo": "value"}))
    # [<div data-foo="value">foo!</div>]
    
    #2.3、按照类名查找,注意关键字是class_,class_=value,value可以是五种选择器之一
    print(soup.find_all('a',class_='sister')) #查找类为sister的a标签
    print(soup.find_all('a',class_='sister ssss')) #查找类为sister和sss的a标签,顺序错误也匹配不成功
    print(soup.find_all(class_=re.compile('^sis'))) #查找类为sister的所有标签
    
    #2.4、attrs
    print(soup.find_all('p',attrs={'class':'story'}))
    
    #2.5、text: 值可以是:字符,列表,True,正则
    print(soup.find_all(text='Elsie'))
    print(soup.find_all('a',text='Elsie'))
    
    #2.6、limit参数:如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果
    print(soup.find_all('a',limit=2))
    
    #2.7、recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .
    print(soup.html.find_all('a'))
    print(soup.html.find_all('a',recursive=False))
    
    '''
    像调用 find_all() 一样调用tag
    find_all() 几乎是Beautiful Soup中最常用的搜索方法,所以我们定义了它的简写方法. BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同,下面两行代码是等价的:
    soup.find_all("a")
    soup("a")
    这两行代码也是等价的:
    soup.title.find_all(text=True)
    soup.title(text=True)
    '''
    View Code

      其他方法:

    #见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#find-parents-find-parent

     css选择器:select,后面直接写上css的查找方式。

    #该模块提供了select方法来支持css,详见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
    html_doc = """
    <html><head><title>The Dormouse's story</title></head>
    <body>
    <p class="title">
        <b>The Dormouse's story</b>
        Once upon a time there were three little sisters; and their names were
        <a href="http://example.com/elsie" class="sister" id="link1">
            <span>Elsie</span>
        </a>
        <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
        <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
        <div class='panel-1'>
            <ul class='list' id='list-1'>
                <li class='element'>Foo</li>
                <li class='element'>Bar</li>
                <li class='element'>Jay</li>
            </ul>
            <ul class='list list-small' id='list-2'>
                <li class='element'><h1 class='yyyy'>Foo</h1></li>
                <li class='element xxx'>Bar</li>
                <li class='element'>Jay</li>
            </ul>
        </div>
        and they lived at the bottom of a well.
    </p>
    <p class="story">...</p>
    """
    from bs4 import BeautifulSoup
    soup=BeautifulSoup(html_doc,'lxml')
    
    #1、CSS选择器
    print(soup.p.select('.sister'))
    print(soup.select('.sister span'))
    
    print(soup.select('#link1'))
    print(soup.select('#link1 span'))
    
    print(soup.select('#list-2 .element.xxx'))
    
    print(soup.select('#list-2')[0].select('.element')) #可以一直select,但其实没必要,一条select就可以了
    
    # 2、获取属性
    print(soup.select('#list-2 h1')[0].attrs)
    
    # 3、获取内容
    print(soup.select('#list-2 h1')[0].get_text())
    View Code

     修改文档数:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id40

     总结:

    # 总结:
    #1、推荐使用lxml解析库
    #2、讲了三种选择器:标签选择器,find与find_all,css选择器
        1、标签选择器筛选功能弱,但是速度快
        2、建议使用find,find_all查询匹配单个结果或者多个结果
        3、如果对css选择器非常熟悉建议使用select
    #3、记住常用的获取属性attrs和文本值get_text()的方法
    

     二 pyquery模块

    Windows下的安装:
    下载地址:https://pypi.python.org/pypi/pyquery/#downloads
    下载后安装:

    1
    C:Python27>easy_install E:pythonpyquery-1.2.4.zip

    也可以直接在线安装:

    1
    C:Python27>easy_install pyquery

    pyquery是一个类似jquery的python库,可以使用像jquery那样的语法来提取网页中的任何数据,这个用于html网页的数据提取和挖掘还是一个很不错的第三方库的。下面我们来看下pyquery的用法有哪些。

    从html字符串中提取信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
     
    from pyquery import PyQuery as pq
    html = '''
    <html>
    <head>
     <title>this is title</title>
    </head>
    <body>
     <p id="hi">Hello, World</p>
     <p id="hi2">Nihao</p>
     <div class="class1">
      <img src="1.jpg" />
     </div>
     <ul>
      <li>list1</li>
      <li>list2</li>
     </ul>
    </body>
    </html>
    '''
    d=pq(html)
     
    print d('title') # 相当于css选择器,根据html标签获取元素
    print d('title').text() # text()方法获取当前选中的文本块
     
    print d('#hi').text() # 相当于id选择器,直接根据id名获取元素
    print d('p').filter('#hi2').text() # 可以根据idclass得到指定元素
    print d('.class1') # 相当于class选择器
    print d('.class1').html() # html()方法获取当前选中的html块
    print d('.class1').find('img').attr('src') # 查找嵌套元素,并选中属性
    print d('ul').find('li').eq(0).text() # 根据索引号获取多个相同html元素中的某一个
    print d('ul').children() # 获取所有子元素
    print d('ul').children().eq(0) #根据索引获取子元素
    print d('img').parents() # 获取父元素
    print d('#hi').next() # 获取下一个元素
    print d('#hi').nextAll() #获取后面全部元素块
    print d('p').not_('#hi2') # 返回不匹配选择器的元素
    # 遍历所有匹配的元素
    for i in d.items('li'):
     print i.text()
    print [i.text() for i in d.items('li')] # 遍历用于列表推倒
    print d.make_links_absolute(base_url='http://www.baidu.com') # 把html文档中的相对路径变为绝对路径

    上面的代码段给出了pyquery常用的操作方法。我们先定义了一段html代码,然后利用pyquery的一系列方法对该html代码进行了操作,主要是获取特定的元素以及文本等。当然,pyquery不仅仅能够获取元素,还能进行设置元素属性、增加元素等功能,鉴于我们最常用的就是上面代码中用到的方法,这里就不再对其他方法进行介绍了。

    从url或本地html文件中提取信息

    当然,pyquery也不仅仅可以解析像上面的html字符串,还可以这样:

    1
    d = pq(url='http://www.baidu.com/')

    我们可以直接加载一个URL,和上面的操作方法没有任何区别。这种方法默认使用urllib模块进行http请求,但如果你的系统中安装了requests的话,那么就会使用requests来进行http请求,这也就意味着你可以使用requests的任何参数,比如:

    1
    pq('http://www.baidu.com/', headers={'user-agent': 'pyquery'})

    或者,如果你在你的本地已经有了对应的html文件,那么还可以这样:

    1
    d = pq(filename=path_to_html_file)

    上面的写法直接指定了本地的html文件,且操作方法仍然与上面的相同。
    可以看到,pyquery给我们提供充分的便利性来进行任何元素的选取,就像jquery一样。

    利用pyquery抓取豆瓣电影top250

    看完了pyquery的语法,我们来看一个实例,抓取豆瓣电影top250。
    因为豆瓣反爬虫反的厉害,运行几次就没法再抓了,我只好先用requests把页面下载下来,直接使用pyquery分析页面的方法来提取信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from pyquery import PyQuery as pq
    import requests
     
    head_req = {
     'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36',
     
    }
    r=requests.get("https://movie.douban.com/top250?start=0",headers=head_req)
    with open("1.html","wb") as html:
     html.write(r.content)
     
    d=pq(filename="1.html")
     
    # print d('ol').find('li').html()
    for data in d('ol').items('li'):
     print data.find('.hd').find('.title').eq(0).text()
     print data.find('.star').find('.rating_num').text()
     print data.find('.quote').find('.inq').text()
     print

    运行下看看结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    肖申克的救赎
    9.6
    希望让人自由。
     
    这个杀手不太冷
    9.4
    怪蜀黍和小萝莉不得不说的故事。
     
    阿甘正传
    9.4
    一部美国近现代史。
     
    霸王别姬
    9.4
    风华绝代。
     
    美丽人生
    9.5
    最美的谎言。
     
    千与千寻
    9.2
    最好的宫崎骏,最好的久石让。
     
    辛德勒的名单
    9.4
    拯救一个人,就是拯救整个世界。
     
    海上钢琴师
    9.2
    每个人都要走一条自己坚定了的路,就算是粉身碎骨。
     
    机器人总动员
    9.3
    小瓦力,大人生。
     
    盗梦空间
    9.2
    诺兰给了我们一场无法盗取的梦。
     
    泰坦尼克号
    9.1
    失去的才是永恒的。
     
    三傻大闹宝莱坞
    9.1
    英俊版憨豆,高情商版谢耳朵。
     
    放牛班的春天
    9.2
    天籁一般的童声,是最接近上帝的存在。
     
    忠犬八公的故事
    9.2
    永远都不能忘记你所爱的人。
     
    龙猫
    9.1
    人人心中都有个龙猫,童年就永远不会消失。
     
    大话西游之大圣娶亲
    9.1
    一生所爱。
     
    教父
    9.2
    千万不要记恨你的对手,这样会让你失去理智。
     
    乱世佳人
    9.2
    Tomorrow is another day.
     
    天堂电影院
    9.1
    那些吻戏,那些青春,都在影院的黑暗里被泪水冲刷得无比清晰。
     
    当幸福来敲门
    8.9
    平民励志片。
     
    搏击俱乐部
    9.0
    邪恶与平庸蛰伏于同一个母体,在特定的时间互相对峙。
     
    楚门的世界
    9.0
    如果再也不能见到你,祝你早安,午安,晚安。
     
    触不可及
    9.1
    满满温情的高雅喜剧。
     
    指环王3:王者无敌
    9.1
    史诗的终章。
     
    罗马假日
    8.9
    爱情哪怕只有一天。

    当然这只是第一页的25条,我们已经知道了豆瓣电影top250的url是

    https://movie.douban.com/top250?start=0
    start参数从0,每次加25,直到

    https://movie.douban.com/top250?start=225
    所以可以写个循环把它们都抓下来。

     

      

  • 相关阅读:
    流畅的python--函数
    流暢的python---函數闭包
    IDEA2019与Maven3.6以上版本不兼容
    java面试知识点汇总---第一章 重视基础
    《动手学深度学习》task10 文本分类;数据增强;模型微调 课后作业
    《动手学深度学习》task09 优化算法进阶;word2vec;词嵌入进阶 课后作业
    《动手学深度学习》task08 图像分类案例2;GAN;DCGAN 课后作业
    《动手学深度学习》task08GAN;DCGAN 笔记
    《动手学深度学习》task07 目标检测基础;图像风格迁移;图像分类案例1 课后作业
    《动手学深度学习》task07目标检测基础;图像风格迁移 笔记
  • 原文地址:https://www.cnblogs.com/fangjie0410/p/8276888.html
Copyright © 2011-2022 走看看