如何用Python爬取多个页面的数据信息呢?这次通过豆瓣网top250的图书信息来进行学习。首先给出页面(如图1所示)的URL: https://book.douban.com/top250 ,我们要爬去的信息是:书名、链接、评分、一句话评价……
图1
1. 爬取单个信息
首先要是爬取单个页面中单个书本的信息,这个内容上篇文章以及记录过了,代码如下:
import requests
#from lxml import etree
from lxml import html
etree = html.etree
url = 'https://book.douban.com/top250'
data = requests.get(url).text
s=etree.HTML(data)
#通过@title获取他的title标签里面的内容
film=s.xpath('//*[@id="content"]/div/div[1]/div/table[1]/tr/td[2]/div[1]/a/@title')
print('电影名称:',film)
2.爬取多个信息
获取单个页面多个全部书本信息,这样就要看各个页面的xpath的不同:
//*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div[1]/a
//*[@id="content"]/div/div[1]/div/table[2]/tbody/tr/td[2]/div[1]/a
//*[@id="content"]/div/div[1]/div/table[3]/tbody/tr/td[2]/div[1]/a
比较可以发现书名的 xpath 信息仅仅 table 后的序号不一样,并且跟书的序号一致,于是去掉序号(去掉 tbody),我们可以得到通用的 xpath 信息:
//*[@id=“content”]/div/div[1]/div/table/tr/td[2]/div[1]/a
代码
import requests
#from lxml import etree
from lxml import html
etree = html.etree
url = 'https://book.douban.com/top250'
data = requests.get(url).text
s=etree.HTML(data)
#通过@title获取他的title标签里面的内容
film=s.xpath('//*[@id="content"]/div/div[1]/div/table/tr/td[2]/div[1]/a/@title')
for title in film:
print(title)
结果如图2所示:
图2
同理我们去爬出其他信息,这样就遇到一个问题,怎么去定义循环次数呢?那我们爬出的信息一定会在一个总的标签中,我们只需要向上求最大公约数,就可以找到循环次数。我们将整本书和书名的xpath进行对比,后就可以找到。
//*[@id=“content”]/div/div[1]/div/table[1] #整本书
//*[@id=“content”]/div/div[1]/div/table[1]/tr/td[2]/div[1]/a #书名
//*[@id=“content”]/div/div[1]/div/table[1]/tr/td[2]/div[2]/span[2]
获取单个页面全部信息的代码如下,结果如图3所示:
import requests
#from lxml import etree
from lxml import html
etree = html.etree
url = 'https://book.douban.com/top250'
data = requests.get(url).text
s=etree.HTML(data)
#file用来记录循环次数
file=s.xpath('//*[@id="content"]/div/div[1]/div/table')
#通过@title获取他的title标签里面的内容
for info in file:
title = info.xpath('./tr/td[2]/div[1]/a/@title')[0]
href = info.xpath("./tr/td[2]/div[1]/a/@href")[0]
score = info.xpath('./tr/td[2]/div[2]/span[2]/text()')[0]
#只取评论的第一条
commitmentNum=info.xpath('./tr/td[2]/div[2]/span[3]/text()')[0].strip("(").strip().strip(")")
scribe=info.xpath("./tr/td[2]/p[2]/span/text()")
print("{} {} {} {}".format(title,href,score,commitmentNum,scribe[0]))
图3
3.翻页,爬取所有页面信息
先来看一下翻页后url是如何变化的:
https://book.douban.com/top250?start=0 #第一页
https://book.douban.com/top250?start=25 #第二页
https://book.douban.com/top250?start=50 #第三页
url 变化的规律很简单,只是 start=() 的数字不一样而已,而且是以每页25为单位,递增25,这不正是每页的书籍的数量吗?于是,我们只需要写一个循环就可以了,结果如图4所示。
import requests
#from lxml import etree
from lxml import html
for a in range(10):
url = 'https://book.douban.com/top250?start={}'.format(a*25)
data = requests.get(url).text
etree = html.etree
s=etree.HTML(data)
#file用来记录循环次数
file=s.xpath('//*[@id="content"]/div/div[1]/div/table')
#通过@title获取他的title标签里面的内容
for info in file:
title = info.xpath('./tr/td[2]/div[1]/a/@title')[0]
href = info.xpath("./tr/td[2]/div[1]/a/@href")[0]
score = info.xpath('./tr/td[2]/div[2]/span[2]/text()')[0]
#只取评论的第一条
commitmentNum=info.xpath('./tr/td[2]/div[2]/span[3]/text()')[0].strip("(").strip().strip(")")
scribe=info.xpath("./tr/td[2]/p[2]/span/text()")
#防止没有评论出现
if len(scribe) > 0:
print("{} {} {} {} {}\n".format(title,href,score,commitmentNum,scribe[0]))
else:
print("{} {} {} {}\n".format(title,href,score,scribe))
图4
4、问题及总结
①得到第一本书《追风筝的人》的书名xpath如下:
//*[@id="content"]/div/div[1]/div/table[1]/tbody/tr/td[2]/div[1]/a
然后运行,发现竟然为空值,这里需要注意,浏览器复制的 xpath 信息并不是完全可靠的,浏览器经常会自己在里面增加多余的 tbody 标签,我们需要手动把这些标签删掉。
②在这些代码中
title = div.xpath("./tr/td[2]/div[1]/a/@title")[0]
score=div.xpath("./tr/td[2]/div[2]/span[2]/text()")[0]
为什么这两行后面多了个 [0] 呢?我们之前爬出来的数据是列表,外面带个方框,看着非常难受,列表只有一个值,对其取第一个值就OK。
③有一个点需要注意的是:
num=div.xpath("./tr/td[2]/div[2]/span[3]/text()")[0].strip("(").strip().strip(")")
这行代码用了几个 strip() 方法,()里面表示要删除的内容,strip(“(”) 表示删除左括号, strip() 表示删除空白符,strip(")"表示删除右括号。
④上面翻页的时候URL变化格式是个重点,为了加深印象我们增加一个练习,看下面的URL代码变化:
http://cd.xiaozhu.com/search-duanzufang-p1-0/ #第一页
http://cd.xiaozhu.com/search-duanzufang-p2-0/ #第二页
http://cd.xiaozhu.com/search-duanzufang-p3-0/ #第三页
http://cd.xiaozhu.com/search-duanzufang-p4-0/ #第四页
url 变化的规律很简单,只是 p 后面的数字不一样而已,而且跟页码的序号是一模一样的,这就很好办了……写一个简单的循环来遍历所有的url。
#我们这里尝试5个页面
for a in range(1,6):
url = ‘http://cd.xiaozhu.com/search-duanzufang-p{}-0/’.format(a)
⑤如何将数据存到本地文档
写文件时,我们主要用到 with open() 语句:
with open(name,mode,encoding) as file:
file.write()
# 注意,with open() 后面的语句有一个缩进
- name:包含文件名称的字符串,比如:‘xiaozhu.txt’;
- mode:决定了打开文件的模式,只读/写入/追加等;
- encoding:表示我们要写入数据的编码,一般为 utf-8 或者 gbk ;
- file:表示我们在代码中对文件的命名。如图5所示
import requests#from lxml import etree
from lxml import html
with open('C:/Users/Administrator/Desktop/1.csv','w',encoding='utf-8') as f:
for a in range(10):
url = 'https://book.douban.com/top250?start={}'.format(a*25)
data = requests.get(url).text
etree = html.etree
s=etree.HTML(data)
file=s.xpath('//*[@id="content"]/div/div[1]/div/table')
for info in file:
title = info.xpath('./tr/td[2]/div[1]/a/@title')[0]
href = info.xpath("./tr/td[2]/div[1]/a/@href")[0]
score = info.xpath('./tr/td[2]/div[2]/span[2]/text()')[0]
commitmentNum=info.xpath('./tr/td[2]/div[2]/span[3]/text()')[0].strip("(").strip().strip(")")
scribe=info.xpath("./tr/td[2]/p[2]/span/text()")
if len(scribe) > 0:
f.write("{},{},{},{},{}\n".format(title,href,score,commitmentNum,scribe[0]))
else:
f.write("{},{},{},{}\n".format(title, href, score, commitmentNum))
⑥Excel 打开 CSV 出现乱码怎么办?
在记事本中打开文件
另存为 – 选择编码为“ANSI”