前言

写在前边

这篇内容可以算是回忆录,因此没有图片,如果后期需要相应的项目,我可能会考虑添加图片。

产生原因

Python爬虫在之前稍微学过一点,但是并不完整。

写这个的原因是一个课设需要做书籍销售信息系统设计,因此需要许多书籍信息。

这里是上文提到的信息系统设计的传送门

首先想到的办法就是直接用python通过一定规则,随机生成书籍信息,这个方法是最快的,但是生成结果看起来有一点点的weird奇怪

因为使用的生成规则比较少,尤其是生成的书籍名称,听起来完全不像是正常的书籍名称。

其他想法

直接从网上寻找数据库

这个方法有限制,比如书籍内容有限制,每一本书籍需要的信息可能并不全,或者是数据库提供的信息不是我想要的

因此我决定自己写一个爬虫来解决这个问题。

正文

在本文最后,有代码完整代码贴上,因此可以不用复制每一个代码框

需要引入的头文件

核心头文件

我是用的是Anaconda安装的python和其他包,个人认为这个方式比较简单(我比较懒)。

1
2
import urllib.request  # 用去获取网站链接请求
from bs4 import BeautifulSoup # 用于读取网站内容

决定写入的文件名

爬取的文件,我是用了Excel文件保存,这里是用了filename作为文件名,如下,最终保存的文件为Excel_test1.xlsx

1
2
3
4
filename = "Excel_test1.xls" # 储存文件名
workbook = xlwt.Workbook()
sheet = workbook.add_sheet(" ") # 创建一个空的sheet,否则不能保存文件
workbook.save(filename) # 这里是文件名字

有的小可爱可能发现了为什么我下边写的文件名和上边的不同。这并不是笔误。

因为我最后需要使用mysql构建数据库,使用Navicat导入Excel文件时,xls文件无法成功导入,因此我加入了文件转换模块,将xls文件转换为了xlsx文件。
下边是文件转换模块用到的代码

1
2
3
4
5
6
7
8
def turn2XLSX(filename):
fname = "D:\\Alask\\Desktop\\ExperimentTwo\\"+filename
excel = win32.gencache.EnsureDispatch('Excel.Application')
wb = excel.Workbooks.Open(fname)

wb.SaveAs(fname+"x", FileFormat = 51) #FileFormat = 51 is for .xlsx extension
wb.Close() #FileFormat = 56 is for .xls extension
excel.Application.Quit()

输入模块

main函数中(并不是python的__main__)中,拥有下述内容

1
keyword = [r"东野圭吾",r"python",r"乙一",r"心里",r"陆秋槎",r"信息系统设计"] # 关键词列表

可以修改上述内容设置多个爬取关键词,一定要使用双引号括起来关键词!

设置页面数量

main函数中(并不是python的__main__)中,拥有下述内容

1
start(keyword,2 ,True) # bool:是否只创建一个表;int: 页面数

第二个int参数代表每个关键词爬取的页面数量,每一个页面中具体数量由当当网页面决定。

修改生成内容顺序

kore函数中,可以修改生成文件中每一项的排序顺序。

在下述代码中,您可以修改其顺序,来改变生成文件中的列顺序。

1
2
3
4
5
6
7
8
sheet.write(0,0,"id")
sheet.write(0,1,"题目")
sheet.write(0,2,"ISBN")
sheet.write(0,3,"作者")
sheet.write(0,4,"定价")
sheet.write(0,5,"售价")
sheet.write(0,6,"出版社")
sheet.write(0,7,"类别")

如果您修改了上述代码顺序,您同样需要对下述代码的顺序进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
allMessage = list(zip(title,author,pre_price,now_price,publisher, ISBN, classies, idNumbers))

iicount = 1
for item in allMessage:
if(item[5].isdigit()):
sheet.write(count,0, item[7]) # id
sheet.write(count,1, item[0]['title']) # title
sheet.write(count,2, item[5]) # ISBN
sheet.write(count,3, item[1]) # Author
sheet.write(count,4, item[2].string) # pre_price
sheet.write(count,5, item[3].string) # now_price
sheet.write(count,6, item[4].string) # publisher
sheet.write(count,7, item[6]) # classifies

该代码块中allMessage代表了暂存爬取数据的块,其顺序如其名称所示,下边的item[]中顺序和allMessage顺序保持一致即可。

在上述代码中,使用item的顺序显然不是按照自然数顺序使用的,理由如上一句。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# -*- coding: utf-8 -*-

import os
import urllib.request # 用去获取网站链接请求
from urllib.parse import quote # 用于中文的URL编码转换

import openpyxl
import win32com.client as win32
import xlwt # 用于写入Excel
from bs4 import BeautifulSoup # 用于读取网站内容
from xlrd import open_workbook # 打开Excel进行二次写入
from xlutils.copy import copy
import time


filename = "Excel_test1.xls" # 储存文件名
workbook = xlwt.Workbook()
sheet = workbook.add_sheet(" ") # 创建一个空的sheet,否则不能保存文件
workbook.save(filename) # 这里是文件名字

def findISBN(s):
findContent = "国际标准书号ISBN:"
isbnStartPosition = s.rfind(findContent)+len(findContent)
isbn = s[isbnStartPosition:isbnStartPosition+13]
return isbn
def findId(s):
findContent = "http://product.dangdang.com/"
idStartPosition = s.rfind(findContent)+len(findContent)
idNumber = s[idStartPosition:-5]
return idNumber
def kore(keyword,ranges = 1, flag = False):
'''
按照关键词查找书籍信息的核心代码
'''
rexcel = open_workbook(filename) # 用wlrd提供的方法读取一个excel文件
excel = copy(rexcel) # 用xlutils提供的copy方法将xlrd的对象转化为xlwt的对象
if(flag):table = excel.get_sheet(" ") # 用xlwt对象的方法获得要操作的sheet
else:table = excel.add_sheet(keyword) # 用xlwt对象的方法获得要操作的sheet
excel.save(filename) # xlwt对象的保存方法,这时便覆盖掉了原来的excel
sheet = table
sheet.write(0,0,"id")
sheet.write(0,1,"题目")
sheet.write(0,2,"ISBN")
sheet.write(0,3,"作者")
sheet.write(0,4,"定价")
sheet.write(0,5,"售价")
sheet.write(0,6,"出版社")
sheet.write(0,7,"类别")

if(flag):count = rexcel.sheets()[0].nrows # 用wlrd提供的方法获得现在已有的行数
else:count = 1
# ranges = 1 # 查找的页面最大值
icount = 1
for i in range(1, ranges+1):
url = "http://search.dangdang.com/?key={}&act=input&page_index={}".format(quote(keyword, 'utf-8'), i)

f = urllib.request.urlopen(url)
html = f.read().decode('gb18030')
# .decode('GB2312')
# html = f.read()
soup = BeautifulSoup(html, "html.parser")



title = soup.findAll(name="a", attrs={"name":"itemlist-title"})
author = []
ps = soup.findAll(name='p',attrs={"class":"search_book_author"})
for p in ps:
author.append(p.a.string)
# author = soup.findAll(name="a", attrs={"name":"itemlist-author"})
pre_price = soup.findAll(name="span", attrs={'class':'search_pre_price'})
now_price = soup.findAll(name="span", attrs={'class':'search_now_price'})
publisher = soup.findAll(name="a", attrs={'name':'P_cbs'})

message = list(zip(title,author,pre_price,now_price,publisher))

ISBN = [] # 国际索书号
classies = [] # 书籍类别
idNumbers = [] # 图书id
loopStop = 0
for k in list(title):
loopStop+=1
if(loopStop>=20):
loopStop = 0
time.sleep(0.5)
icount = icount + 1

childurl = k.get('href')
idNumbers.append(findId(childurl))
ff = urllib.request.urlopen(childurl)

bookImformationHtml = ff.read()
bookSoup = BeautifulSoup(bookImformationHtml, "html.parser")

li = bookSoup.find(name="ul", attrs={"class":"key clearfix"})
tmp = findISBN(str(li))
ISBN.append(tmp)

classify = bookSoup.findAll(name = "a",attrs={"class":"green"})
tmpClass = [] # 临时用于保存书籍类别的list
for a_ in classify:
if(a_.string != "图书"):
tmpClass.append(a_.string)
tmpClass.append(".")
classies.append(tmpClass[:-1])

os.system('cls')
print("关键词:",keyword)
print("正在获取 : ",icount,"/ ", ranges*len(title))
print("获取链接: " + childurl)
print("ID: " + findId(childurl))
print("书名: " + k['title'])
print("国际索书号ISBN: " + tmp)
print("分类: " + ("".join(tmpClass[:-1])).replace('.','>'))

allMessage = list(zip(title,author,pre_price,now_price,publisher, ISBN, classies, idNumbers))

iicount = 1
for item in allMessage:
if(item[5].isdigit()):
sheet.write(count,0, item[7]) # id
sheet.write(count,1, item[0]['title']) # title
sheet.write(count,2, item[5]) # ISBN
sheet.write(count,3, item[1]) # Author
sheet.write(count,4, item[2].string) # pre_price
sheet.write(count,5, item[3].string) # now_price
sheet.write(count,6, item[4].string) # publisher
sheet.write(count,7, item[6]) # classifies
count = count + 1

os.system('cls')
print("关键词:",keyword)
print("正在写入缓存 : ",iicount," / ", len(allMessage))
iicount = iicount + 1
excel.save(filename) # xlwt对象的保存方法,这时便覆盖掉了原来的excel
time.sleep(1) # 暂停 1 秒


def turn2XLSX(filename):
fname = "D:\\Users\\Desktop\\IS_design\\"+filename
excel = win32.gencache.EnsureDispatch('Excel.Application')
wb = excel.Workbooks.Open(fname)

wb.SaveAs(fname+"x", FileFormat = 51) #FileFormat = 51 is for .xlsx extension
wb.Close() #FileFormat = 56 is for .xls extension
excel.Application.Quit()

def start(keyword, ranges = 1,flag = False):
for k in keyword:
kore(k, ranges,flag)
os.system('cls')
print("写入完成,正在转换文件格式")
turnFileName = filename+'x'
if os.path.exists(turnFileName): # 删除现有文件
os.remove(turnFileName)
turn2XLSX(filename) # 转换文件格式
if(flag == False): deleteSheet(turnFileName," ") # 删除空sheet

def deleteSheet(sExcelFile, sheet):
'''
删除开始时候建的空sheet
'''
wb = openpyxl.load_workbook(sExcelFile)
ws = wb[sheet]
wb.remove(ws)
wb.save(sExcelFile)
print("文件转换完成")



def main():
keyword = [r"东野圭吾",r"python",r"乙一",r"心里",r"陆秋槎",r"信息系统设计"] # 关键词列表
start(keyword,2 ,True) # bool:是否只创建一个表;int: 页面数
os.system('cls')
print("已完成")

if __name__=="__main__":
main()


结语

代码最后适用日期:2020-04-21
根据上述内容,可以爬取相应的书籍信息数据。如果后期当当网的结构发生改变,改程序拥有不再适用的可能性,请注意!

在运行本代码时,可能会由于网络原因,或者是各种各样的问题,该程序无法顺利运行。这个时候可以尝试多次运行该程序。

但是请注意,爬虫该行为本身是否合法是有待商榷的。

这里附上项目的仓库

其中formal.py文件为上述程序代码,CreateStock.py为整理成我需要的格式所创建的代码,这里不做叙述,请各位小可爱自行研究,欢迎留言。

Excel_test1.xxx文件为formal.py程序生成的文件,或者根据该文件转换的文件。

StockInfo.xxx文件为CreateStock.py程序生成的文件,或者根据该文件转换的文件。


参考内容

爬虫究竟是否合法:https://www.zhihu.com/question/291554395

当当网界面:http://search.dangdang.com/?key=��Ұ����&act=input

其他内容:由于时间过于久远,无法溯源,如果有小伙伴发现上述内容和其他哪个小可爱的内容重复了,可以给我留言,我会及时增添参考链接或者是删除内容。