一:爬虫
1、爬取的目标
将读书网上的书籍的基本信息,比如:封面、书名、作者、出版社、价格、出版时间、内容简介、作者简介、书籍目录、ISBN和标签爬取出来,并将爬取的结果放入数据库中,方便存储。
2、网站结构
图1读书网书籍类别详情
此次实验爬取读书网页面中文学、小说、传记、青春文学、艺术、散文随笔、励志、人文社科、经济管理、励志十大类书籍。
每一类书籍包括书名、价格、作者、出版社、ISDN、出版时间、封面以及书籍简介、作者简介、书目录和书籍所属类别。页面具体情况如图2所示。
图2读书网书籍属性设计详情
3、爬虫技术方案
1)、所用技术:
网站解析的使用的是Xpath、数据库存储使用的是pymysql。
2)、爬取步骤:
(1)、分析目标网站:了解页面结构;
(2)、获取页面内容:使用python中的requests库来获取页面内容;
(3)、定位页面:使用Xpath定位我们所需要的数据的位置;
(4)、连接数据库:创建数据连接,放入自己数据库的端口、用户和密码等数据,使得连接上自己的数据库,将爬取好的数据返给数据库中,方便存储;
(5)、关闭连接:关闭数据库连接。
4、爬取过程:
1)、常量定义
此处定义了网页后缀END=‘.html’用于进行网页拼接。
Start_Page = 1 定义爬取起始页码,end_Page = 10 定义爬取结束页码。
Base_url 用于设置爬取网页的基础网站,进行后续网页拼接。
Book_type={},该字典设置爬取书籍类别。
Header={},该字典进行请求头设置。
2)、设置游标,连接数据库,再使用for循环,确保书籍能够循环爬取,最后将爬取完毕的数据放入数据库中,最后关闭数据库的连接。
3)、一级链接爬取,接收参数基本网页地址、书籍类型、网页页数后,再使用requests库中r.get(url=url,headers=header)发送请求,使用response接收请求数据。
4)、二级链接爬取,在数据获取步骤,进行更细致的xpath语句书写。
使用try-except语句提高程序健壮性,返回一个书籍信息字典。
5)、保存数据,创建游标,编写sql语言,之后执行sql语言,执行成功就插入所给的表,如果执行失败则输出插入失败。
5、爬虫结果
二:预处理
-
删除列
1)、新建转换,之后使用表输入,将MySQL文件中的表输入kettle。需要连接数据库的类型是MySQL,主机名称是localhost、用户是root、密码是root、端口号是3306。
之后进行字段获取。
2)、选择转换中的字段选择进行列删除,将dictroy这个列进行删除。
2、选择转换中的增加常量,增加remainder这一列,查询书籍卖出剩余的情况。
-
、最后选择文本文件输出,将处理好的数据输出,输出的格式是csv文件,分割符用逗号隔开,编码用UTF-8J进行转码,防止输出文件中有乱码。文本文件命名为姓名_处理完成_csv。
4、预处理完全处理全流程
三、爬虫源代码
import re
import requests
from lxml import etree
import pymysql
import datetime
"""
爬取一个网站
1.获得数据不小于一千条
2.每条数据属性不小于10
"""
END = '.html'
start_Page = 1
end_Page = 10
base_url = 'https://www.dushu.com'
# 以字典形式保存每一类对应的网页数字
book_type = {"文学": 1077, "小说": 1078, "传记": 1081, "青春文学": 1079,
"艺术": 1082, "散文随笔": 1163, "鉴赏": 1222, "人文社科": 1003,
"经济管理": 1004, "励志": 1094
}
header = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'
}
def get_one_bookInfo_link(base_url, _type, page):
# url 控制爬取的书籍类型、网页页数
url = base_url+'/book/'+str(_type)+'_'+str(page)+END
# print(url)
response = requests.get(url=url, headers=header)
if response.status_code == 200:
htmlTEXT = response.content.decode(response.apparent_encoding)
html = etree.HTML(htmlTEXT)
bookLinke_List = html.xpath('//div[@class="container margin-top"]//div[@class="bookslist"]/ul/li/div[@class="book-info"]/h3/a/@href')
return bookLinke_List
else:
print("请求失败")
def get_oneBook_info(bookLinke):
url = base_url + bookLinke
content = requests.get(url=url, headers=header)
if content.status_code == 200:
info = etree.HTML(content.content.decode(content.apparent_encoding))
# 获取书籍详细信息,十个
try:
img = info.xpath('//div[@class="bookdetails-left"]/div[@class="book-pic"]//img/@src')[0] # 封面
title = info.xpath('//div[@class="bookdetails-left"]/div[@class="book-pic"]//img/@alt')[0] # 书名
author = info.xpath('//div[@id="ctl00_c1_bookleft"]/table//tr[1]//td[2]/text()')[0] # 作者
publish = info.xpath('//div[@id="ctl00_c1_bookleft"]/table//tr[2]//td[2]/text()')[0] # 出版社
temp_price = info.xpath('//div[@id="ctl00_c1_bookleft"]/p/span/text()')[0] # 价格
price = temp_price.split('¥')[1]
time = info.xpath('//div[@class="bookdetails-left"]/div[@class="book-details"]/table//tr[1]/td[@class="rt"][2]/text()')[0] # 出版时间
cont = info.xpath('//div[@class="container margin-top"]//div[contains(@class, "book-summary")][1]/div/div/text()')[0] # 内容简介
blurb = info.xpath('//div[@class="container margin-top"]//div[contains(@class, "book-summary")][2]/div/div/text()')[0] # 作者简介
directory = info.xpath('//div[@class="container margin-top"]//div[contains(@class, "book-summary")][3]/div/div/text()')[0] # 书籍目录
isbn = info.xpath('//div[@class="bookdetails-left"]/div[@class="book-details"]/table//tr[1]/td[@class="rt"][1]/text()')[0] # ISBN
label = info.xpath('//div[@id="ctl00_c1_bookleft"]/table//tr[4]//td[2]/text()')[0] # 标签
# 使用字典保存一本书籍的信息
book_info = {
"img": img,
"title": title,
"author": author,
"publish": publish,
"price": price,
"time": time,
"cont": cont,
"blurb": blurb,
"directory": directory,
"isbn": isbn,
"label": label
}
return book_info
except Exception as e:
print("爬取时单本书籍获取出现错误:", e, "\n发生错误地址为:"+url)
err_info = {
"img": 'https://a.dushu.com/img/n200.png',
"title": 'titleEro',
"author": 'authorEro',
"publish": 'publishEro',
"price": '00.00',
"time": '2001-01-01',
"cont": 'contEro',
"blurb": 'blurbEro',
"directory": 'directoryEro',
"isbn": 'isbnEro',
"label": 'labelEro'
}
return err_info
else:
print("请求失败")
def set_BookInfo_ToMySql(book_info, db):
# print(book_info.values())
cursor = db.cursor()
# sql语句
sql = "INSERT INTO book(img,title,author,publish,price,time,cont,blurb,directory,isbn,label) VALUES " \
"('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')"\
%(book_info["img"], book_info["title"], book_info["author"], book_info["publish"],
book_info["price"], book_info["time"], book_info["cont"], book_info["blurb"],
book_info["directory"], book_info["isbn"], book_info["label"])
print(book_info.values())
try:
# 执行sql语句
if cursor.execute(sql):
print('插入数据成功')
# 提交到数据库执行
db.commit() # 持久化
except Exception as e:
# 如果发生错误则回滚
print("插入失败", e)
db.rollback()
def main():
# 用于存储计算数据爬取数量
count = 0
# 连接数据库
db = pymysql.connect(host='localhost', user='root', password='root', port=3306, db='pachong')
# 开启爬取程序
for type in book_type: # 控制爬取书籍的类别
for i in range(start_Page, end_Page+1): # 控制每一类爬取的页数
# 每一个网页的书籍的二级连接
bookLinke_List = get_one_bookInfo_link(base_url=base_url, _type=book_type[type], page=i)
if bookLinke_List:
for link in bookLinke_List:
print(link)
info = get_oneBook_info(link)
info['label'] = type
# print(info)
set_BookInfo_ToMySql(book_info=info, db=db)
count += 1
else:
print("爬取内容为空")
# 数据插入完成后关闭数据库
if db:
db.close()
print("关闭数据库成功,程序结束")
else:
print("数据加载成功,数据库未关闭")
return count
if __name__ == '__main__':
print("Run...")
# 获取开始时间
start_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
# db = pymysql.connect(host='localhost', user='root', password='root', port=3306, db='movie')
# info = get_oneBook_info('/book/13981332/')
# set_BookInfo_ToMySql(info, db=db)
# db.close()
print("已爬取书籍数量:", main())
# 获取结束时间
end_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print("程序结束{}\n运行开始时间:{}".format(end_time, start_time))