python3爬取豆瓣排名前250名的图书摘要信息

188 阅读4分钟

豆瓣读书:book.douban.com/top250?star…

第一步:使用XPATH分析豆瓣的Top250图书排行榜

为了便于查看XPath分析html的整个过程我们把网页的源码下载下来,使用文本编辑器WebStorm打开,该文本编辑器可以清楚的查看标签的对应关系。

查看源码发现每一本书的摘要信息都保存在一个标签

内,标签有一个唯一识别的id=“conetent”

捕获.PNG

使用XPATH查找content:

先获取content标签下的内容吗

import requests
from lxml import etree
# 设置访问客户端头部信息,不设置可能无法使用requests访问
headers = {'User-Agent': 'M'}
book_url = 'https://book.douban.com/top250?start=0'
resp = requests.get(book_url,headers=headers)
# 获取响应的所有源码信息
book_resp_text = resp.text
# 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
book_etree_element = etree.HTML(book_resp_text)
book_url1 = book_etree_element.xpath('//*[@id="content"]')
book_url2 = book_etree_element.xpath('//*[@id="content"]/@id')
print(book_url1)
print(book_url2)

输出结果:

[<Element div at 0x1c145e0b080>]
['content']

[<Element div at 0x1c145e0b080>]是对象的输出对象

['content']是对应的标签

Xpath代码解析:

xpath('//*[@id="content"]')
// # 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
* # 通配符匹配所有
[@id="content"] # 匹配标签属性,本次这个id属性是唯一的所以可以匹配到一个唯一的标签

注意:匹配代码如果有多个引号则内部和外部不能使用相同的引号符号,即外部使用单引号则内部需要使用双引号,反之亦然

查找独立内容整个模块的最小标签item

import requests
from lxml import etree
# 设置访问客户端头部信息,不设置可能无法使用requests访问
headers = {'User-Agent': 'M'}
book_url = 'https://book.douban.com/top250?start=0'
resp = requests.get(book_url,headers=headers)
# 获取响应的所有源码信息
book_resp_text = resp.text
# 使用etree.HTML转换成可以使用xpath分析的lxml.etree._Element对象
book_etree_element = etree.HTML(book_resp_text)
book_url1 = book_etree_element.xpath('//tr[@class="item"]')
book_url2 = book_etree_element.xpath('//tr[@class="item"]/@class')
print(book_url1)
print(book_url2)
print(len((book_url2)))

每一个的25个书本的详细信息都是在这个标签里面

需要从item中获取的内容定位

获取书籍名字:

#书名在title="红楼梦"中获取
for info in book_url1:
    bookname=info.xpath('td/div/a/@title')[0]
print(type(bookname))
print(bookname)

获取书籍的详情页面:

    bookinfo = info.xpath('td/p/text()')[0]
    # 作者
    author = bookinfo.split('/')[0]
    # 出版社
    publish = bookinfo.split('/')[-3]
    # 出版日期
    date = bookinfo.split('/')[-2]
    # 价格
    price = bookinfo.split('/')[-1]

获取评价分数和评价:

        # 评价分数
        quotes = info.xpath('td[2]/div[2]/span[2]/text()')[0]
        comments = info.xpath('td/p/span/text()')
        comment = comments[0] if len(comments) != 0 else "空"

写入内容:

每一次遍历都要追加的写入:

        df.append([bookname, bookurl, author, publish,date, price, quotes, comments])
        d = pd.DataFrame(df, columns=columns)
        d.to_excel('Top250书籍.xlsx', index=False)

第二步:使用函数爬取数据并存储到Excell

主要目的:检查爬取函数是否有效

import requests
from lxml import etree
import pandas as pd
df = []
# 使用UA值
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4343.0 Safari/537.36',
    'Referer': 'https://book.douban.com/top250'}
# 数据的第一行的每一列的标题,一共   8个    标题,后续处理数据的时候,针对此列的数据进行处理
columns = ['书籍名称', '书籍详情页面', '作者', '出版社', '出版年份', '价格', '豆瓣评分', '短评']
​
​
def get_data(html):
    selector = etree.HTML(html)  # 解析网页
    # 取大标签,以此类推
    # <tr class='item'>
    infos = selector.xpath('//tr[@class="item"]')
    for info in infos:
        bookname = info.xpath('td/div/a/@title')[0]
        bookurl = info.xpath('td/div/a/@href')[0]  # 详情页
        #   /text是获取到定位元素的文本值
        bookinfo = info.xpath('td/p/text()')[0]
        # 作者
        author = bookinfo.split('/')[0]
        # 出版社
        publish = bookinfo.split('/')[-3]
        # 出版日期
        date = bookinfo.split('/')[-2]
        # 价格
        price = bookinfo.split('/')[-1]
        # 评价分数
        quotes = info.xpath('td[2]/div[2]/span[2]/text()')[0]
        comments = info.xpath('td/p/span/text()')
        comment = comments[0] if len(comments) != 0 else "空"
        df.append([bookname, bookurl, author, publish,date, price, quotes, comments])
        d = pd.DataFrame(df, columns=columns)
        d.to_excel('Top250书籍.xlsx', index=False)
​
​
for i in range(0, 251, 25):
    # 遍历开始翻页,每一页是25个书籍,第一页是1-25条,第二页就是26-50条,依次类推到250条
    url = "https://book.douban.com/top250?start={}&filter=".format(str(i))
    res=requests.get(url, headers=headers)
    html = res.text  # 获取问本值
    get_data(html)  # 传入参数
    print("执行完毕!")
​

第三步:并发爬取

import pandas as pd
import time
import requests
from lxml import etree
from queue import Queue
from threading import Thread, Lock
​
​
class Book_250():
    def __init__(self):
        self.df = []
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4343.0 Safari/537.36',
            'Referer': 'https://book.douban.com/top250?start=0'}
        # 数据的第一行的每一列的标题,一共   8个    标题,后续处理数据的时候,针对此列的数据进行处理
        self.columns = [
            '书籍名称',
            '书籍详情页面',
            '作者',
            '出版社',
            '出版年份',
            '价格',
            '豆瓣评分',
            '短评']
        self.lock = Lock()
        self.url_list = Queue()
​
    def get_url(self):  # b遍历每一个大的页面,也就是包括25个书籍的页面
        url = "https://book.douban.com/top250?start={}&filter="
        for i in range(0, 250, 25):
            self.url_list.put(url.format(str(i)))
​
    def get_html(self):  # 获取解析的网页全部
        while True:
            if not self.url_list.empty():
                url = self.url_list.get()
                resp = requests.get(url, headers=self.headers)
                html = resp.text
                self.xpath_parse(html)
            else:
                break
​
    def xpath_parse(self, html):  # 解析网页的过程
        selector = etree.HTML(html)  # 解析网页
        # 取大标签,以此类推
        # <tr class='item'>
        infos = selector.xpath('//tr[@class="item"]')
        for info in infos:
            bookname = info.xpath('td/div/a/@title')[0]
            bookurl = info.xpath('td/div/a/@href')[0]  # 详情页
            #   /text是获取到定位元素的文本值
            bookinfo = info.xpath('td/p/text()')[0]
            # 作者
            author = bookinfo.split('/')[0]
            # 出版社
            publish = bookinfo.split('/')[-3]
            # 出版日期
            date = bookinfo.split('/')[-2]
            # 价格
            price = bookinfo.split('/')[-1]
            # 评价分数
            quotes = info.xpath('td[2]/div[2]/span[2]/text()')[0]
            comments = info.xpath('td/p/span/text()')
            comment = comments[0] if len(comments) != 0 else "空"
            self.df.append([bookname, bookurl, author, publish,
                           date, price, quotes, comments])
            d = pd.DataFrame(self.df, columns=self.columns)
            d.to_excel('并发250书籍.xlsx', index=False)
​
    def main(self):  # 执行步骤
        start_time = time.time()
        # 第一步,获取网页地址
        self.get_url()
        # 第二步,
        th_list = []
        for i in range(5):
            th = Thread(target=self.get_html)
            th.start()
            th_list.append(th)
        # 第三步:
        for th in th_list:
            th.join()
        end_time = time.time()
        print(end_time - start_time)
​
​
if __name__ == "__main__":
    spider = Book_250()
    spider.main()
    print("执行完毕!")

数据存储在了同一级的目录下