zoukankan      html  css  js  c++  java
  • 一起学爬虫——使用xpath库爬取猫眼电影国内票房榜

    之前分享了一篇使用requests库爬取豆瓣电影250的文章,今天继续分享使用xpath爬取猫眼电影热播口碑榜

    XPATH语法
    XPATH(XML Path Language)是一门用于从XML文件中查找信息的语言。通用适用于从HTML文件中查找数据。工欲善其事必先利其器,我们首先来了解XPATH常用的语法规则。

    常用匹配规则:

    属性 匹配规则描述
    nodename 匹配此节点的所有子节点
    / 匹配当前节点的直接子节点,不包含孙节点
    // 匹配当前节点的所有子孙节点
    . 匹配当前节点
    .. 匹配当前节点的父节点
    @ 匹配属性值

    XPATH的匹配功能很强大,上面6种匹配规则可以搭配使用,通过上面的6种匹配规则即可爬取到网页上所有的我们想要的数据。

    使用下面的HTML文档介绍上述6种规则的搭配使用。

    <html>
        <div id="div_id1" class="div_class1">
            <ul>
                <li class="li_item1"><a href="www.bigdata17.com">Summer哥的自留地</a></li>
                <li class="li_item2 li"><a href="li_test.html">test li</a></li>
            </ul>
                <li>20</li>
                <li>30</li>
            <ul>
            </ul>
        </div>
    </html>
    
    匹配表达式 结果
    //* 匹配网页中所有的节点
    //div 匹配所有div节点
    //div/li 匹配所有div节点的所有li节点
    //a[@href="www.bigdata17.com"/..] 匹配href属性为www.bigdata17.com的A节点的父节点
    //li[@class="li_item1"] 匹配所有li元素,且为class属性为"li_item1"
    //li[@class] 匹配所有拥有class属性的li元素
    //li/a/@href 获取所有li元素a子元素的href属性值,注意和//li[@class="li_item1"的且
    //li//text() 过去li节点所有子节点的文本
    //li[@class="li_item1"]/a/text() 获取class属性为li_item1的li节点所有a子节点的文本
    //li[contains(@class,"li")]/a/text() 获取class属性值包含li的li节点所有a子节点的文本
    //div[contains(@class,"div") and @id="div_id1"]/ul 获取所有class属性包含“div”且id属性值为“div_id1”的div节点的ul子节点
    /div/ul[li>20] 选取div节点的所有 ul节点,且其中的li节点的值须大于20
    /div/ul[1] 匹配属于div节点的第一个 ul节点。
    /div/ul[last()] 匹配属于div 子节点的最后一个ul节点
    /div/ul[last()-1] 匹配属于div 子节点的倒数第二个ul节点
    /div/ul[position() < 3] 匹配最前面的两个属于div元素的ul子元素

    通过上面的匹配规则,我们就可以使用XPATH来解析爬取猫眼电影国内票房榜的数据。

    XPATH要配合requests一起使用,使用requests抓取网页信息,然后使用XPATH解析网页信息,XPATH在lxml库中,因此需要在pycharm中安装lxml。

    1、获取取猫眼电影热播口碑榜HTML文件
    下面是抓取猫眼电影热播口碑榜的代码:

    from lxml import etree
    import requests
    
    url = 'http://maoyan.com/board/1'
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
    response = requests.get(url,headers=headers)
    html = response.text
    

    2、提取电影名
    现在浏览器的开发者工具都支持提取xpath规则,具体步骤如下:
    首先在浏览器中打开网址,按下F12,ctrl+f查找电影名,鼠标右键弹出的菜单,点击Copy选项,点击Copy Xpath。到此就可以把电影名称的xpath匹配规则提取出来:
    python xpath

    电影名称提取的规则是:
    //*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a

    我们使用这个规则看下是否能提取出电影名称,代码如下:

    from lxml import etree
    import requests
    
    url = 'http://maoyan.com/board/7'
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
    response = requests.get(url,headers=headers)
    html = response.text
    
    movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a/text()'
    s = etree.HTML(html)
    movie_name = s.xpath(movie_name_xpath)
    print(movie_name)
    

    运行结果:[<Element a at 0x35f5248>]
    上面的结果显示抓取到的是a元素,就是html中的a标签,要想获取该元素中的文本值,必须在xpath匹配规则追加/text(),下面是追加/text()后的代码及运行结果:

    from lxml import etree
    import requests
    
    url = 'http://maoyan.com/board/1'
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
    response = requests.get(url,headers=headers)
    html = response.text
    
    movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a/text()'
    s = etree.HTML(html)
    movie_name = s.xpath(movie_name_xpath)
    print(movie_name)
    
    运行结果['嗝嗝老师']
    

    这里只是提取一部电影的名称,我们要想提取当前网页的所有电影的名称,匹配规则怎么写呢?
    下面是当前页10部电影的xpath匹配规则

    //*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[2]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[3]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[4]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[5]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[6]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[7]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[8]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[9]/div/div/div[1]/p[1]/a
    //*[@id="app"]/div/div/div/dl/dd[10]/div/div/div[1]/p[1]/a
    

    发现dd的数字会变化,其他的都不变,因此用通配符“*”代替dd节点中的数字,提取当前页所有电影名字的xpath规则为:

    //*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a
    

    看下最后的运行结果是什么。

    from lxml import etree
    import requests
    
    url = 'http://maoyan.com/board/1'
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
    response = requests.get(url,headers=headers)
    html = response.text
    
    movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a/text()'
    s = etree.HTML(html)
    movie_name = s.xpath(movie_name_xpath)
    print(movie_name)
    
    运行结果:['嗝嗝老师', '毒液:致命守护者', '无名之辈', '恐龙王', '流浪猫鲍勃', '无双', '名侦探柯南:零的执行人', '飓风奇劫', '影', '你好,之华']
    

    可见使用通配符*把所有的电影名称都提取出来了。

    3、提取电影图片链接
    通过上步骤获取图片的xpath匹配规则为:

    //*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]
    

    通过开发者工具知道img节点有三个属性,分别是alt,class和src。
    python xpath
    其中src的是图片的地址,在xpath提取规则追加上@src,变为:

    //*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@src
    

    看下这个xpath规则是否能提取到图片的链接地址:

    from lxml import etree
    import requests
    
    url = 'http://maoyan.com/board/7'
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
    response = requests.get(url,headers=headers)
    html = response.text
    
    movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@src'
    s = etree.HTML(html)
    movie_img = s.xpath(movie_img_xpath)
    print(movie_img)
    

    运行的结果是:[]

    怎么会得不到src属性的值呢?难道src属性不存在?

    通过鼠标右键查看网页源文件:
    python xpath
    原来src变成了data-src。修改xpath规则后看下能否提取出电影图片链接:

    from lxml import etree
    import requests
    
    url = 'http://maoyan.com/board/7'
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
    response = requests.get(url,headers=headers)
    html = response.text
    
    movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@data-src'
    s = etree.HTML(html)
    movie_img = s.xpath(movie_img_xpath)
    print(movie_img)
    

    运行结果:

    ['http://p0.meituan.net/movie/36f1a50b4eae6aa93e3f7a373fb6ee89991083.jpg@160w_220h_1e_1c']
    

    电影图片链接提取成功。
    这是提取一部电影的xpath规则,下面是当前页面10部电影图片的规则:

    //*[@id="app"]/div/div/div/dl/dd[1]/a/img[2]/@data-src
    //*[@id="app"]/div/div/div/dl/dd[2]/a/img[2]/@data-src
    //*[@id="app"]/div/div/div/dl/dd[3]/a/img[2]/@data-src
    ...
    ...
    ...
    //*[@id="app"]/div/div/div/dl/dd[9]/a/img[2]/@data-src
    //*[@id="app"]/div/div/div/dl/dd[10]/a/img[2]/@data-src
    

    观察发现dd的数字会变化,其他的都不变,因此用通配符“*”代替dd节点中的数字,提取当前页所有电影图片链接的xpath规则为:

    //*[@id="app"]/div/div/div/dl/dd[*]/a/img[2]/@data-src
    

    以此类推,通过上面的方式提取出当前页所有电影名称,图片地址,主演,上映时间,评分的xpath匹配规则:

    movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a/text()'
    movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/a/img[2]/@data-src'
    movie_actor_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[2]/text()'
    movie_release_time_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[3]/text()'
    movie_score_xpath = 
    '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[2]/p/i/text()'
    

    爬取猫眼电影国内热播榜的完整代码如下:

    # coding:utf-8
    from lxml import etree
    import requests
    
    #获取网页
    def getHtml(url):
        headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0"}
    
        response = requests.get(url,headers=headers)
        html = response.text
        return html
        #
        # movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[1]/div/div/div[2]/p/i/text()'
        # s = etree.HTML(html)
        # movie_img = s.xpath(movie_img_xpath)
        # print(movie_img)
    
    #解析网页
    def parseHtml(html):
        s = etree.HTML(html)
        movie_name_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[1]/a/text()'
        movie_img_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/a/img[2]/@data-src'
        movie_actor_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[2]/text()'
        movie_release_time_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[1]/p[3]/text()'
        movie_score_xpath = '//*[@id="app"]/div/div/div/dl/dd[*]/div/div/div[2]/p/i/text()'
    
        movie_name = s.xpath(movie_name_xpath)
        movie_img = s.xpath(movie_img_xpath)
        movie_actor = s.xpath(movie_actor_xpath)
        movie_score = s.xpath(movie_score_xpath)
        movie_release_time = s.xpath(movie_release_time_xpath)
    
        for i in range(len(movie_name)):
            print('电影名称:' + movie_name[i])
            print('主演:' + movie_actor[i].strip())
            print('图片链接:' + movie_img[i].strip())
            print('评分:' + movie_score[2*i] + movie_score[2*i + 1])
            print(movie_release_time[i])
            print('-------------------------------------------强力分割线-------------------------------------------')
    def main():
        url = 'http://maoyan.com/board/7'
        html = getHtml(url)
        parseHtml(html)
    
    if __name__ == '__main__':
        main()
    

    总结:
    在使用开发者工具提取xpath规则获取不到相应的数据时,要注意xpath规则是否准确,有些浏览器会加上一些多余的标签,或者将节点的属性名改掉,例如上面例子中将的img节点的src属性变为data-src。结合查看源文件都可以获取到正确的xpath规则。

  • 相关阅读:
    PHP浮点数引起的四舍五入问题
    几项有用的JQUERY代码
    php5.5新特性之yield理解
    【转】循环、迭代、遍历和递归
    phpexcel导入excel文件报the filename xxx is not recognised as an OLE file错误。
    php缩放gif和png格式透明背景变成黑色的解决方法
    javascript统计输入文本的简易方法
    分享几个实用的jquery工具函数
    thinkphp中ajax技术
    正斜杠与反斜杠
  • 原文地址:https://www.cnblogs.com/airnew/p/9997662.html
Copyright © 2011-2022 走看看