爬取豆瓣图书TOP250图书信息及图书海报

写这篇主要是为了去图书馆不知道看什么书或者不知道该买些什么书的时候可以参考经过众多豆友们点评出的好书推荐,哈哈哈哈哈。

上代码(全部代码均在这里,只是分开按照步骤解释一下)
第一步:导入需要用到的包。

from bs4 import BeautifulSoup        # 网页解析,获取数据
import urllib.request, urllib.error  # 指定url,获取网页数据
import re                            # 正则表达式,进行文字匹配
import xlwt                          # 进行excel操作
import requests

第二步:定义主函数。

def main():
    baseurl = "https://book.douban.com/top250?start="
    datalist = getData(baseurl)        # 爬数函数,见第四步
    savepath = ".\\豆瓣图书Top250.xls"  # 将爬取的信息保存到当前目录下的Excel表中
    saveData(datalist, savepath)       # 保存数据函数,见第六步

第三步:删除html中的多余空格,以便更好的存储在Excel中,此时不删也可以,等存入Excel中之后使用Excel中的替换操作替换掉空格(也可以直接写在爬数函数中,这里就直接封装了)。

def remove(string):
    pattern = re.compile(r'\s+')
    return re.sub(pattern, '', string)

第四步:定义爬数函数。

def getData(baseurl):
    datalist = []             # 用于存放所有书的信息
    for i in range(10):       # 调用获取页面信息的函数,一共10页,根据豆瓣图书的链接规律得到
        # 1、生成访问链接
        baseurl = "https://book.douban.com/top250?start="
        url = baseurl + str(i*25)
        html = askURL(url)    # 爬取网页函数,见第五步

        # 2、解析数据
        soup = BeautifulSoup(html, "html.parser")
        for item in soup.find_all('tr', class_='item'):
            # 根据html网页可以看到每本书是一个item
            item = str(item)
            data = []    # 用于存放一本书的所有信息

            # 3、正则表达式提取图书信息
            # 图书详情的链接
            link = re.search('<a href="(.*?)" onclick.*?>', item)
            data.append(link.group(1))             # 添加链接

            # 图书书名
            name = re.search('<a.*?title="(.*?)">', item)
            data.append(name.group(1))
            print("书名:", name.group(1))

            # 图书海报的链接
            img_src = re.search('<img src="(.*?)".*?>', item)
            data.append(img_src.group(1))

            # 保存图书海报图片
            # 根据自己的文件夹修改保存路径
            string = 'D:/MyData/PycharmProjects/pythonProject/图书海报/'+"/"+str(name.group(1)) + ".jpg"
            try:
                photo = requests.get(img_src.group(1), timeout=10)  # 可能有些图片网址打不开,故设置一个10秒的超时控制
                fp = open(string, 'wb')
                fp.write(photo.content)
                fp.close()
            except Exception:  # 出现异常直接跳过
                print("图片无法下载")
                continue  # 跳出本次循环

            # 作者、译者、出版社、出版日期、价格
            # 由于html中这部分信息是在一个<p></p>中,故利用/来判断,计算/的个数
            info = re.search('<p class="pl">(.*?)</p>', item)
            num = 0
            for i in info.group(1):
                if i == '/':
                    num += 1
            print("num:", num)
			
			# 中文图书,包含作者、出版社、出版日期和价格四个信息
            if num == 3:
                # 图书作者
                author = re.search('<p class="pl">(.*?) / .*?</p>', item)
                data.append(author.group(1))
                print("作者:", author.group(1))

                # 图书译者,无译者信息,空格表示,以下同理
                data.append(" ")

                # 图书出版社
                publisher = re.search('<p class="pl">.*? / (.*?) / .*?</p>', item)
                data.append(publisher.group(1))
                print("出版社:", publisher.group(1))

                # 图书出版日期
                publish_date = re.search('<p class="pl">.*? / .*? / (.*?) / .*?</p>', item)
                data.append(publish_date.group(1))
                print("出版日期:", publish_date.group(1))

                # 图书价格
                price = re.search('<p class="pl">.*? / .*? / .*? / (.*?)</p>', item)
                data.append(price.group(1))
                print("价格:", price.group(1))
			
			# 英文图书,包含作者、译者、出版社、出版日期和价格五个信息
			# (=4包含一个价格,=5包含两个价格)
            elif num == 4 or num == 5:
                # 图书作者
                author = re.search('<p class="pl">(.*?) / .*?</p>', item)
                data.append(author.group(1))
                print("作者:", author.group(1))

                # 图书译者
                tran = re.search('<p class="pl">.*? / (.*?) / .*?</p>', item)
                data.append(tran.group(1))
                print("译者:", tran.group(1))

                # 图书出版社
                publisher = re.search('<p class="pl">.*? / .*? / (.*?) / .*?</p>', item)
                data.append(publisher.group(1))
                print("出版社:", publisher.group(1))

                # 图书出版日期
                publish_date = re.search('<p class="pl">.*? / .*? / .*? / (.*?) / .*?</p>', item)
                data.append(publish_date.group(1))
                print("出版日期:", publish_date.group(1))

                # 图书价格
                price = re.search('<p class="pl">.*? / .*? / .*? / .*? / (.*?)</p>', item)
                data.append(price.group(1))
                print("价格:", price.group(1))
			
			# 只包含出版社、出版日期和价格的图书,如论语、十万个为什么等书
            elif num == 2:
                # 图书作者
                data.append(" ")

                # 图书译者
                data.append(" ")

                # 图书出版社
                publisher = re.search('<p class="pl">(.*?) / .*?</p>', item)
                data.append(publisher.group(1))
                print("出版社:", publisher.group(1))

                # 图书出版日期
                publish_date = re.search('<p class="pl">.*? / (.*?) / .*?</p>', item)
                data.append(publish_date.group(1))
                print("出版日期:", publish_date.group(1))

                # 图书价格
                price = re.search('<p class="pl">.*? / .*? / (.*?)</p>', item)
                data.append(price.group(1))
                print("价格:", price.group(1))

            # 图书评分
            rating = re.search('<span class="rating_nums">(.*?)</span>', item)
            data.append(rating.group(1))
            print("评分:", rating.group(1))

            # 图书评价人数-此处调用了去除空格函数
            rat_num = re.search('<span class="pl">\((.*?)人评价.*?', item, re.S)
            rat_numer = remove(rat_num.group(1))
            data.append(rat_numer)
            print("评分人数:", remove(rat_num.group(1)))

            # 图书概况-有的图书没有概况,空格表示
            inq = re.search('<span class="inq">(.*?)</span>', item)
            if inq is not None:
                data.append(inq.group(1))
                print("概况:", inq.group(1))
                print('\n')
            else:
                data.append(" ")

            datalist.append(data)     # 把处理好的一本书的信息加入datalist
    return datalist

第五步:定义爬取网页函数。head部分的作用及获得方法。

def askURL(url):
    head = {   # 伪装浏览器,向豆瓣服务器发送消息
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36"
    }
    request = urllib.request.Request(url, headers=head)
    html = ""
    try:
        response = urllib.request.urlopen(request)
        html = response.read().decode("utf-8")
        # print(html)
    except urllib.error.URLError as e:
        if hasattr(e, "code"):
            print(e.code)
        if hasattr(e, "reason"):
            print(e.reason)
    return html

第六步:保存数据函数。

def saveData(datalist, savepath):
   	# 1、创建workbook对象
    book = xlwt.Workbook(encoding="utf-8", style_compression=0)  
    # 2、sheet表信息
    sheet = book.add_sheet('豆瓣图书TOP250', cell_overwrite_ok=True)  # 创建工作表
    # 3、写入数据
    col = ('图书详情链接', "图书书名", "图书海报链接", "图书作者", "图书译者 ", "图书出版社", "图书出版日期", "图书价格", "图书评分", "图书评价人数", "概况")
    for i in range(11):
        sheet.write(0, i, col[i])   # 列名
    for i in range(250):
        data = datalist[i]
        for j in range(11):
            sheet.write(i+1, j, data[j])

    book.save(savepath)  # 保存数据表

第七步:大功告成函数。

if __name__ == "__main__":
    main()
    print("报告警长,任务完成!")

以上就是爬取的全流程啦,爬取的部分结果看下图。

先看Excel表格中存储的数据:

python爬取豆瓣影评 BeautifulSoup 教程 基于python爬取豆瓣图书信息_爬虫


再来看图书海报:

python爬取豆瓣影评 BeautifulSoup 教程 基于python爬取豆瓣图书信息_正则表达式_02


大功告成啦!关于第四步爬数函数中的正则表达式部分,若不理解可参考知乎文章,讲解很详细。爬虫再次提醒哦:爬虫千万条,安全第一条。