爬当当各分类下的五星图书

@DC学院《Python爬虫:入门+进阶》

报名了DC学员的爬虫课程,断断续续学了两个星期,才看完第一章。虽然技术还很菜,但一些基本的东西能够爬取了,也想趁这次作业,来尝试一下这段时间学习的知识。

这次作业选择爬取的网站是当当网,一方面是因为传说比较简单,另一方面也有比较多的图书数据,特别是五星图书,包含了各个领域最受欢迎的图书信息,对于寻找有价值的图书、分析好书的一些情况具有一定的价值。

废话不多说,先上准备爬取的页面链接:
http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-all-0-0-1-1

具体的页面如下图:
《爬当当各分类下的五星图书》 当当网五星图书页面


我想爬取的数据是各分类(小说、中小学教辅、文学、成功/励志……)下面的五星图书信息(书名、评论数、作者、出版社、出版时间、五星评分次数、价格、电子书价格等等)。

为了抓各分类下的图书信息,首先看看点击各分类的时候,链接是否发生变化。经过测试,在不同的分类,链接都是不一样的,事实证明不是JS加载。

于是,第一步就是要获取不同分类的页面链接,先以“小说”类目作为样例来测试一下,复制xpath信息并获取链接。

《爬当当各分类下的五星图书》 复制”小说”类目的xpath信息


得到的xpath如下:

//*[@id="sortRanking"]/div[2]/a


按照固定的套路,尝试获取类目标题和页面链接:

from lxml import etree
import requests

url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-all-0-0-1-1'
data = requests.get(url).text
s = etree.HTML(data)

title = s.xpath('//*[@id="sortRanking"]/div[2]/a/text()')
href = s.xpath('//*[@id="sortRanking"]/div[2]/a/@href')

print(title)
print(href)

顺利地得到了类目的名称和链接:
《爬当当各分类下的五星图书》 尝试获取各第一个类目的名称和链接


到这里基本可以知道,当当网的反爬确实不严格,我甚至还没有设置Headers的信息,竟然也可以爬取到想要的数据。但最后在完整的代码中,还是把headers加上了,保险起见吧。

既然这样,其他的链接也可以通过这样的方式来获取,于是比较了一下多个类目的xpath,很容易发现规律。获取所有的类目链接如下:

from lxml import etree
import requests

url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-all-0-0-1-1'
data = requests.get(url).text
s = etree.HTML(data)
items = s.xpath('//*[@id="sortRanking"]/div')

for item in items:
    book_url=item.xpath('./a/@href')
    item_name=item.xpath('./a/text()')

    if len(book_url)>0:  #避免抓回来的链接是空的情况
        href=book_url[0]
        item_title=item_name[0]
        print(item_title)
        print(href)

《爬当当各分类下的五星图书》 爬回来的部分的链接

接下来就是分别爬取每个分类下的图书信息,以“小说”为例,其实翻页特别简单,给几个比较如下:

http://bang.dangdang.com/books/fivestars/01.03.00.00.00.00-all-0-0-1-1
http://bang.dangdang.com/books/fivestars/01.03.00.00.00.00-all-0-0-1-2
http://bang.dangdang.com/books/fivestars/01.03.00.00.00.00-all-0-0-1-3
…………………………

翻页也非常简单,只不过有一点点坑的是,爬回来的链接在代码中,需要对其翻页,就需要把链接构造出来。对返回来的链接进行分析,发现仅仅是中间有四个数字不一样。于是我把这几个数据取出来,在连接中传进去,这样可以构造通用的链接。

对于翻页的数量,粗略地看了一下各个类目的最大页数,最多的是25页,当然也有少于25页的。

于是构造出每个类目下都有25个页面的链接:

from lxml import etree
import requests
import time

url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-all-0-0-1-1'
data = requests.get(url).text
s = etree.HTML(data)
items = s.xpath('//*[@id="sortRanking"]/div')

for item in items:
    book_url=item.xpath('./a/@href')
    item_name=item.xpath('./a/text()')

    if len(book_url)>0:
        href=book_url[0]
        item_title=item_name[0]
        a=href[41:46]
        print(item_title)
    
        for page in range(1,26):
            per_url= 'http://bang.dangdang.com/books/fivestars/{}.00.00.00.00-all-0-0-1-{}'.format(a,page)
            print(per_url)

《爬当当各分类下的五星图书》 构造的翻页链接-小说
《爬当当各分类下的五星图书》 构造的翻页链接-中小学教辅

接下来就是去抓取不同页面的信息,没有异步加载,所以直接用xpath定位就OK。当然中间有一些小地方需要注意的是,每本书所包含的信息是不一样的,所以用xpath去获取的时候不一定能获取到,就会出错。

完整的代码如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from lxml import etree
import requests
import time

url = 'http://bang.dangdang.com/books/fivestars/01.00.00.00.00.00-all-0-0-1-1'

headers = {
            'Host': 'bang.dangdang.com',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
        }

data = requests.get(url,headers=headers).text
s = etree.HTML(data)

with open('dangdang.csv','w') as outputfile:
    items = s.xpath('//*[@id="sortRanking"]/div')

    for item in items:
        book_url=item.xpath('./a/@href')
        item_name=item.xpath('./a/text()')

        if len(book_url)>0:
            href=book_url[0]
            item_title=item_name[0]
            a=href[41:46]
            print(item_title)

            for page in range(1,26):

                per_url= 'http://bang.dangdang.com/books/fivestars/{}.00.00.00.00-all-0-0-1-{}'.format(a,page)
                data2=requests.get(per_url).text
                f=etree.HTML(data2)

                try:
                    file=f.xpath('//ul[@class="bang_list clearfix bang_list_mode"]/li')
                    print('正在打印{}第{}页…………'.format(item_title,page))
                    time.sleep(2)

                    for book in file:
                        title=book.xpath('./div[@class="name"]/a/@title')[0]
                        author=book.xpath('string(./div[@class="publisher_info"][1])')
                        pinglun=book.xpath('./div[@class="star"]/a/text()')[0].strip('条评论')
                        wuxing=book.xpath('./div[@class="biaosheng"]/span/text()')[0].strip('次')
                        price_now=book.xpath('./div[@class="price"]/p/span[1]/text()')[0]
                        price_before=book.xpath('./div[@class="price"]/p/span[2]/text()')[0]
                        price_sale=book.xpath('./div[@class="price"]/p/span[3]/text()')[0]

                        try:
                            date=book.xpath('./div[@class="publisher_info"]/span/text()')[0]
                        except:
                            date='出版时间不详'

                        try:
                            company=book.xpath('./div[@class="publisher_info"][2]/a/text()')[0]
                        except:
                            company='出版社不详'

                        try:
                            price_e=book.xpath('./div[@class="price"]/p[@class="price_e"]/span/text()')[0]
                        except:
                            price_e="没有电子书"

                        outputfile.write('{},{},{},{},{},{},{},{},{},{}'.format(title,author,date,company,pinglun,wuxing,price_now,price_before,price_sale,price_e))

                except:
                    pass

爬取的数据如下:
《爬当当各分类下的五星图书》 爬取数据截图
《爬当当各分类下的五星图书》 爬取数据截图

总共10000多行数据,对应不同领域的10000多本高评分的书籍,当然会有一些重复计算,比如小说和文学,就有不少书是同时在这两个类目的。不过不管怎么说,都拿到了数据。

当当网本身没有什么反爬机制,所以爬取也比较顺利。唯一的小麻烦就是抓回来的链接继续翻页和其中一些书籍中部分信息缺失的处理。当然,这些对于稍微有点经验的同学来说都不是什么事。

这次写爬虫,确实也是一次比较系统地尝试,之前也没爬过这么多的数据。自知技术来不够拿到优秀作业和奖励,但是非常高兴能从中获得提升,大神们见笑了。

    原文作者:ZhuNewNew
    原文地址: https://www.jianshu.com/p/8279f38dbe6e
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞