爬虫的抓取方式有好几种,正则表达式,Lxml(xpath)与BeautifulSoup,我在网上查了一下资料,了解到三者之间的使用难度与性能

三种爬虫方式的对比。

这样一比较我我选择了Lxml(xpath)的方式了,虽然有三种方式,但肯定是要选择最好的方式来爬虫,这个道理大家都懂,另外有兴趣的朋友也可以去了解另外两种爬虫方式!

好了现在来讲讲xpath

由于Xpath属于lxml模块,所以首先需要安装lxml库,老办法直接在file-->setting---project interpreter 一键添加lxml库。

xpath简单用法

from lxml import etree

s=etree.HTML(源码) #将源码转化为能被XPath匹配的格式

s.xpath(xpath表达式) #返回为一列表,

基础语法:

  1. // 双斜杠 定位根节点,会对全文进行扫描,在文档中选取所有符合条件的内容,以列表的形式返回。

  2. / 单斜杠 寻找当前标签路径的下一层路径标签或者对当前路标签内容进行操作

  3. /text() 获取当前路径下的文本内容

  4. /@xxxx 提取当前路径下标签的属性值

  5. | 可选符 使用|可选取若干个路径 如//p | //div 即在当前路径下选取所有符合条件的p标签和div标签。

  6. . 点 用来选取当前节点

  7. .. 双点 选取当前节点的父节点

学以致用,方能让我们能快速掌握xpath语法功能。

我们这次需要爬取豆瓣音乐前250条

打开豆瓣音乐:https://music.douban.com/top250

获取单条数据

1.获取音乐标题

打开网址,按下F12,然后查找标题,右键弹出菜单栏 Copy==> Copy Xpath

这里我们想获取音乐标题,音乐标题的xpath是:xpath://*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div/a

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. url = 'https://music.douban.com/top250'
  6.  
  7. html = requests.get(url).text #这里一般先打印一下html内容,看看是否有内容再继续。
  8. s = etree.HTML(html)
  9. title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div/a')
  10. print title

运行代码:
居然是空的。!!!
这里需要注意一下,浏览器复制的xpath只能作参考,因为浏览器经常会在自己里面增加多余的tbody标签,我们需要手动把这个标签删除
删除中间的/tbody后,是这样的,
title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a')
然后我们再运行代码。
得到:
<Element a at 0x53d26c8>

说明标题被获取到了。
因为要获取标题文本,所以xpath表达式要追加/text()
title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/text()')#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()

又因为这个s.xpath返回的是一个集合,且集合中只有一个元素所以我再追加一个[0]
新的表达式:
title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text(),再追加[0]

重新运行得到结果:
We Sing. We Dance. We Steal Things.
正是我们想要的标题。

2.获取音乐评分与评价人数

老办法,先用右键copy评分的xpath ://*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div/div/span[2]
复制评价人数的xpath://*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div/div/span[3]/text()

同样的我们要把tbody去掉,然后重新运行代码:

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. url = 'https://music.douban.com/top250'
  6.  
  7. html = requests.get(url).text
  8. s = etree.HTML(html)
  9. title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  10. score = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/div/span[2]/text()')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  11. numbers = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/div/span[3]/text()')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  12. print title,score,numbers

得到:

We Sing. We Dance. We Steal Things.
   9.1
               (
                       100395人评价
               )

3.获取音乐链接

copy标题的xpath,://*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div/a

想获取音乐连接href这里需要,获取这个标签属于,/@xxx可以提取当前路径标签下的属性值
//*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div/a/@href

代码:

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. url = 'https://music.douban.com/top250'
  6.  
  7. html = requests.get(url).text
  8. s = etree.HTML(html)
  9. href = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/@href')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  10. title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  11. score = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/div/span[2]/text()')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  12. numbers = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/div/span[3]/text()')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  13. print href,title,score,numbers

运行代码得到:

  1. https://music.douban.com/subject/2995812/
               We Sing. We Dance. We Steal Things.
           9.1
                       (
                               100395人评价
                       )
5.获取图片地址:

找到图片,复制他的xpath地址://*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[1]/a/img

运行代码:

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. url = 'https://music.douban.com/top250'
  6.  
  7. html = requests.get(url).text
  8. s = etree.HTML(html)
  9. href = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/@href')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  10. title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  11. score = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/div/span[2]/text()')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  12. numbers = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/div/span[3]/text()')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  13. imgpath = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[1]/a/img/@src')[0]#因为要获取文本,所以我需要这个当前路径下的文本,所以使用/text()
  14. print href,title,score,numbers,imgpath

老套路:
得到结果:

  1. https://music.douban.com/subject/2995812/
               We Sing. We Dance. We Steal Things.
           9.1
                       (
                               100395人评价
                       )
                    https://img3.doubanio.com/spic/s2967252.jpg

但是这只是获取了一条数据,如果获取多条数据呢?

获取多条数据

我们再看第二条数据,第三条数据,第四条数据
得到他们的xpath:

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. url = 'https://music.douban.com/top250'
  6.  
  7. html = requests.get(url).text
  8. s = etree.HTML(html)
  9. title = s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  10. title2 = s.xpath('//*[@id="content"]/div/div[1]/div/table[2]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  11. title3 = s.xpath('//*[@id="content"]/div/div[1]/div/table[3]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  12. title4 = s.xpath('//*[@id="content"]/div/div[1]/div/table[4]/tr/td[2]/div/a/text()')[0]#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  13. print title,title2,title3,title4

得到:

  1.        We Sing. We Dance. We Steal Things.
           Viva La Vida
           华丽的冒险
           范特西

对比他们的xpath,发现只有table序号不一样,我们可以就去掉序号,得到通用的xpath信息:
运行代码:

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. url = 'https://music.douban.com/top250'
  6.  
  7. html = requests.get(url).text
  8. s = etree.HTML(html)
  9. titles = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/a/text()')#因为要获取标题,所以我需要这个当前路径下的文本,所以使用/text()
  10.  
  11. for title in titles:
  12. print title.strip()

得到:

  1. We Sing. We Dance. We Steal Things.
    Viva La Vida
    华丽的冒险
    范特西
    後。青春期的詩
    是时候
    Lenka
    Start from Here
    旅行的意义
    太阳
    Once (Soundtrack)
    Not Going Anywhere
    American Idiot
    OK
    無與倫比的美麗
    亲爱的...我还不知道
    城市
    O
    Wake Me Up When September Ends
    叶惠美
    七里香
    21
    My Life Will...
    寓言
    你在烦恼什么

其它的信息如:链接地址,评分,评价人数都可以用同样的办法来获取,现在我同时获取多条数据,因为每页数据是25条,所以:
完整代码如下:

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4. url = 'https://music.douban.com/top250'
  5. html = requests.get(url).text
  6. s = etree.HTML(html)
  7. hrefs = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/a/@href')
  8. titles = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/a/text()')
  9. scores = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/div/span[2]/text()')
  10. numbers = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/div/span[3]/text()')
  11. imgs = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[1]/a/img/@src')
  12. for i in range(25):
  13. print hrefs[i],titles[i],scores[i],numbers[i],imgs[i]

得到:
一大批数据了,我就不展示了。有兴趣可以直接copy代码运行.,注意你得装上lxml与requests库.

我们也发现了问题每一个xpath路径特别长,能不能精简一下呢?

5. 精简一下xpath路径
  1. hrefs = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/a/@href')
  2. titles = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/a/text()')
  3. scores = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/div/span[2]/text()')
  4. numbers = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div/div/span[3]/text()')
  5. imgs = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[1]/a/img/@src')

观察发现获取几个关键字段的xpath前缀都是 //*[@id="content"]/div/div[1]/div/table/tr 那我能不能把这些东西提出来呢,让后面的不同的自己去追加,另外这样写也不用管每个页面到底有多少条数据,只管查就行了。所以代码做了一下精简。

  1. url = 'https://music.douban.com/top250'
  2.  
  3. html = requests.get(url).text
  4. s = etree.HTML(html)
  5. trs = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr') #先提取tr之前的节点集合
  6.  
  7. for tr in trs: #遍历tr
  8. href = tr.xpath('./td[2]/div/a/@href')[0] #注意新节点是tr下的节点
  9. title = tr.xpath('./td[2]/div/a/text()')[0]
  10. score = tr.xpath('./td[2]/div/div/span[2]/text()')[0]
  11. number = tr.xpath('./td[2]/div/div/span[3]/text()')[0]
  12. img = tr.xpath('./td[1]/a/img/@src')[0]
  13. print href,title,score,number,img

得到的结果和之前是一样的。

但是,但是,这只是一个页面的数据,我现在想爬取多个页面的数据,怎么办呢?

获取个多页面数据.

观察一下翻页路径:
https://music.douban.com/top250?start=0
https://music.douban.com/top250?start=25
https://music.douban.com/top250?start=50

有没有发现页面只是后面start参数发生了改变,且增长为每次25,并且250条数据正好是10页。
所以我可以遍历这个页面。
代码:

  1. for i in range(10):
    url = 'https://music.douban.com/top250?start={}'.format(i*25)
    print url

得到:

  1. https://music.douban.com/top250?start=0
    https://music.douban.com/top250?start=25
    https://music.douban.com/top250?start=50
    https://music.douban.com/top250?start=75
    https://music.douban.com/top250?start=100
    https://music.douban.com/top250?start=125
    https://music.douban.com/top250?start=150
    https://music.douban.com/top250?start=175
    https://music.douban.com/top250?start=200
    https://music.douban.com/top250?start=225

正是自己要的结果。

好了最后我们把代码拼装在一起,并注意每个方法的用途。

完整代码

  1. # coding:utf-8
  2. from lxml import etree
  3. import requests
  4.  
  5. #获取页面地址
  6. def getUrl():
  7. for i in range(10):
  8. url = 'https://music.douban.com/top250?start={}'.format(i*25)
  9. scrapyPage(url)
  10.  
  11. #爬取每页数据
  12. def scrapyPage(url):
  13. html = requests.get(url).text
  14. s = etree.HTML(html)
  15. trs = s.xpath('//*[@id="content"]/div/div[1]/div/table/tr')
  16.  
  17. for tr in trs:
  18. href = tr.xpath('./td[2]/div/a/@href')[0]
  19. title = tr.xpath('./td[2]/div/a/text()')[0]
  20. score = tr.xpath('./td[2]/div/div/span[2]/text()')[0]
  21. number = tr.xpath('./td[2]/div/div/span[3]/text()')[0]
  22. img = tr.xpath('./td[1]/a/img/@src')[0]
  23. print href, title, score, number, img
  24.  
  25. if '__main__':
  26. getUrl()

Python爬虫:现学现用xpath爬取豆瓣音乐的更多相关文章

  1. Python爬虫小白入门(七)爬取豆瓣音乐top250

      抓取目标: 豆瓣音乐top250的歌名.作者(专辑).评分和歌曲链接 使用工具: requests + lxml + xpath. 我认为这种工具组合是最适合初学者的,requests比pytho ...

  2. 爬虫系列1:Requests+Xpath 爬取豆瓣电影TOP

    爬虫1:Requests+Xpath 爬取豆瓣电影TOP [抓取]:参考前文 爬虫系列1:https://www.cnblogs.com/yizhiamumu/p/9451093.html [分页]: ...

  3. 爬虫系列4:Requests+Xpath 爬取动态数据

    爬虫系列4:Requests+Xpath 爬取动态数据 [抓取]:参考前文 爬虫系列1:https://www.cnblogs.com/yizhiamumu/p/9451093.html [分页]:参 ...

  4. Python爬虫教程-13-爬虫使用cookie爬取登录后的页面(人人网)(下)

    Python爬虫教程-13-爬虫使用cookie爬取登录后的页面(下) 自动使用cookie的方法,告别手动拷贝cookie http模块包含一些关于cookie的模块,通过他们我们可以自动的使用co ...

  5. 爬虫系列(十) 用requests和xpath爬取豆瓣电影

    这篇文章我们将使用 requests 和 xpath 爬取豆瓣电影 Top250,下面先贴上最终的效果图: 1.网页分析 (1)分析 URL 规律 我们首先使用 Chrome 浏览器打开 豆瓣电影 T ...

  6. 爬虫系列(十一) 用requests和xpath爬取豆瓣电影评论

    这篇文章,我们继续利用 requests 和 xpath 爬取豆瓣电影的短评,下面还是先贴上效果图: 1.网页分析 (1)翻页 我们还是使用 Chrome 浏览器打开豆瓣电影中某一部电影的评论进行分析 ...

  7. [Python爬虫] 使用 Beautiful Soup 4 快速爬取所需的网页信息

    [Python爬虫] 使用 Beautiful Soup 4 快速爬取所需的网页信息 2018-07-21 23:53:02 larger5 阅读数 4123更多 分类专栏: 网络爬虫   版权声明: ...

  8. scrapy爬虫框架教程(二)-- 爬取豆瓣电影TOP250

    scrapy爬虫框架教程(二)-- 爬取豆瓣电影TOP250 前言 经过上一篇教程我们已经大致了解了Scrapy的基本情况,并写了一个简单的小demo.这次我会以爬取豆瓣电影TOP250为例进一步为大 ...

  9. python定时器爬取豆瓣音乐Top榜歌名

    python定时器爬取豆瓣音乐Top榜歌名 作者:vpoet mail:vpoet_sir@163.com 注:这些小demo都是前段时间为了学python写的,现在贴出来纯粹是为了和大家分享一下 # ...

随机推荐

  1. Load Testing Socket.IO Web Applications and Infrastructure

    转自:https://medium.com/better-programming/load-testing-socket-io-web-applications-and-infrastructure- ...

  2. Program terminated with signal 6, Aborted. (最后发现是数组越界导致)

    外网崩溃现象: 1.多台物理机中的多个进程消失,而且都是场景进程. 2.core文件都很小,看了 ulimit -a 和 cat proc/pid/limits  (都很正常.看这个是为了以后core ...

  3. 联想M7216NWA墨粉清零:

    在设备就绪状态下,按"功能"键,进入设置菜单,按上下键进行选择,屏幕出现"设备信息"项时按"确认"键,再按上下键选择,当屏幕出现" ...

  4. C语言之“字符”与“字符串”之间的区别解析

    在C语言中,“字符”与“字符串”之间,是有区别的.这一篇文章中,我们将介绍一下,在C语言中的“字符”与“字符串”,它们之间的区别. 首先,一个很明显的区别是: “字符”,使用单引号作为定界符,而“字符 ...

  5. [web] react一些些

    作者:水落斜阳链接:https://www.jianshu.com/p/4fb47009c330来源:简书著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1.react comp ...

  6. Anaconda更新失败简单解决[CondaHTTPError: HTTP 000 CONNECTION FAILED for url]

    问题:conda无法安装更新,报错内容如下:参考链接:conda httperror http none none for url none Anaconda更新失败 conda create -n ...

  7. gcc编译链接std::__cxx11::string和std::string的问题

    今天公司的小伙伴遇到一个问题,这里做一个记录. 问题是这样的,他编译了公司的基础库,然后在程序中链接的时候遇到点问题,报错找不到定义. 用到的函数声明大概是这样的: void function(con ...

  8. SearchLookupEdit 选择后联动

    直接改绑定数据源--实体的属性会导致选择内容变空 所有改相应控件的text然后再写入数据源 最好将需要联动的控件设置成只读 mNoTextEdit.EditValueChanged += (s, e) ...

  9. tensorflow keras analysis

    目录 Q: where is Sequential defined? Q: where is compile()? tensorflow keras analysis code from keras. ...

  10. 如何学会快速调用API

    作为一名苦逼的程序员,在实现各种需求的过程中,总是需要调用各种各样的API,也就是要读各种文档.我们所要做的是弄清楚这些API的参数然后调用即可.说起来非常简单,是实际上却不是这样.现在火爆的机器学习 ...