豆瓣读书:book.douban.com/top250?star…
第一步:使用XPATH分析豆瓣的Top250图书排行榜
为了便于查看XPath分析html的整个过程我们把网页的源码下载下来,使用文本编辑器WebStorm打开,该文本编辑器可以清楚的查看标签的对应关系。
查看源码发现每一本书的摘要信息都保存在一个标签
内,标签有一个唯一识别的id=“conetent”
使用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("执行完毕!")
数据存储在了同一级的目录下