目录
需求:
初版:
初版代码review:
优化:
首次优化后代码:
编写函数,可以指明抓取某职位以及页数实现抓不同职位时(用正则和request),存到同一个excel中的不同sheet中,并将数据存到mysql中
以下是第一次编写代码时的思路
#编写正则
def getjobname(jobname,startnum,endnum):
allresult=[]
jobname1=request.quote(request.quote(jobname))
for i in range(startnum,endnum):
print('正在抓取第',i,'页')
url='https://search.51job.com/list/000000,000000,0000,00,9,99,'+jobname1+',2,'+str(i)+'.html?lang=c&stype=1&postchannel=0000&workyear=99&cotype=99°reefrom=99&jobterm=99&companysize=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=4&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='
response=request.urlopen(url)
html=response.read().decode('gbk')
#编写正则用来提取信息,去掉的东西都用.*?来代替
reg=re.compile('.*?',re.S)
result=re.findall(reg,html)
allresult+=result
这里对jobname进行了解码处理,将函数执行时输入的汉字职位转化为匹配51job代码的值
#存储到xls:
if os.path.exists('51job职位信息.xlsx'):
workbook = load_workbook("51job职位信息.xlsx")
sheetNames = workbook.sheetnames
if jobname in sheetNames:
print("sheetName 重复")
return
else:
sheet=workbook.create_sheet(jobname,len(sheetNames)+1)
sheet.append('职位名,公司名,工作地点,薪资,发布时间'.split(','))
for each in allresult:
sheet.append(each)
else:
workbook=Workbook()
sheet=workbook.active
sheet.title=jobname
sheet.append('职位名,公司名,工作地点,薪资,发布时间'.split(','))
for each in allresult:
sheet.append(each)
workbook.save('51job职位信息.xlsx')
#存储到mysql
connection = pymysql.connect(
host='localhost',
user='root',
password='1234',
db='jobinfo',
charset='utf8'
)
cursor = connection.cursor()
for index, each in enumerate(allresult):
sql = "insert into info values " + str((index + 1,) + each) + ";"
cursor.execute(sql)
connection.commit()
cursor.close()
connection.close()
getjobname('前端开发', 1, 3) #执行函数
代码编写完成后试运行,正常。
将代入‘前端开发’的函数二次运行后,提醒“sheetName 重复”,正常。
更改jobname参数为‘人工智能’再次运行,mysql 报错:
OK,代码编写不严谨的问题来了!
1.将爬虫、excel存储、mysql存储所有功能写到一起,大大降低了代码的再重复利用,一个函数最好只做一件事,改!
2.excel存储部分代码写的重复繁冗,可做精简,改!
3.思维不严谨,忽略了存储过程中的多种可能性,改!
重新理了下思路,对步骤做了细化,看起来严谨了一些。
#编写函数获取网页源码
from urllib import request
def gethtml(Jobname,StartNum,EndNum):
job = request.quote(request.quote(Jobname)) # 将输入的Jobname参数汉字转码
for i in range(StartNum,EndNum):
print('正在抓取第',i,'页') # 输出一个小提示,告知在打印第几页
url='https://search.51job.com/list/000000,000000,0000,00,9,99,'+job+',2,'+str(i)\
+'.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99°reefrom=' \
'99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=' \
'-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='
response=request.urlopen(url)
html=response.read().decode('gbk') # 获取网页字符串 html
print(html) # 打印,查看验证函数运行结果
return html
gethtml('数据分析',1,2) #函数运行
#编写正则,提取网页内容
import re
def getdata(Jobname,StartNum,EndNum):
allresult=[]
for i in range(StartNum,EndNum):
html=gethtml(Jobname,StartNum,EndNum) # 通过运行源码函数获取html
# 编写正则用来提取信息,去掉的东西都用.*?来代替
reg = re.compile('',re.S)
result=re.findall(reg,html) # 获得一页的内容
allresult+=result # 通过循环,将获得的每一页内容添加到allresult中
print(allresult)
return allresult
getdata('数据分析',1,2)
#存储到excel
from openpyxl import Workbook
from openpyxl import load_workbook
import os
def savetoexcel(Jobname,StartNum,EndNum):
data=getdata(Jobname,StartNum,EndNum) # 获取上面爬取的所有数据
#判断文件是否存在
if os.path.exists('51job职位信息.xlsx'):
workbook=load_workbook('51job职位信息.xlsx')
sheetnames = workbook.sheetnames # 获取51job职位信息.xlsx的所有sheet名
#判断sheetname是否存在
if Jobname in sheetnames:
sheet=workbook[Jobname]
values=list(sheet.values) # 获取sheet 的所有内容
non_repeat=list(set(data).difference(set(values))) # 找出data与excel的不重复数据
for each in non_repeat:
sheet.append(each) # 将不重复数据写入
#这里有个小BUG,如果数据里有一个值为空,例:'薪资'为空,则代码不断run出该条数据为不重复数据,会重复写入,需要改进(其他正常)
else:
sheet=workbook.create_sheet(Jobname)
sheet.append('职位名,公司名,工作地点,薪资,发布时间'.split(','))
for each in data:
sheet.append(each)
else:
workbook=Workbook()
sheet=workbook.active
sheet.title=Jobname
sheet.append('职位名,公司名,工作地点,薪资,发布时间'.split(','))
for each in data:
sheet.append(each)
workbook.save('51job职位信息.xlsx')
savetoexcel('IT',1,2)
#存储到mysql
import pymysql
def savetomysql(Jobname,StartNum,EndNum):
connection = pymysql.connect(
host='localhost',
user='root',
password='1234',
db='jobinfo',
charset='utf8'
)
cursor=connection.cursor()
# 如果数据表不存在,则执行建表,这里表名用的是中文表名
cursor.execute('create table if not exists '+Jobname+\
'(id int(11) primary key auto_increment,' \
'jobname varchar(100) not null,' \
'company varchar(100) not null,' \
'address varchar(50),' \
'salary varchar(50),' \
'ptime varchar(50))' \
'default charset utf8;')
cursor.execute('select jobname,company,address,salary,ptime from '+Jobname)
connection.commit()
all = cursor.fetchall()#获取数据表的数据
length = len(all)#获取数据表的最后一个id
count = 0
data=getdata(Jobname,StartNum,EndNum)# 获取爬取的数据
for each in data:
if each not in all: # 确定要写入的数据不在数据表内
count+=1
sql='insert into '+Jobname+' values '+str((count+length,)+each)+';'
cursor.execute(sql)
connection.commit()
cursor.close()
connection.close()
savetomysql('数据分析',5,7)
#这里有个小bug,函数执行时,如果第一次执行和第二次执行,没有更改StartNum,则不会写入新数据(其他正常)
分步骤写完了第一次优化的过程,还有很多改进的地方,最明显的就是代码验证时发现的两个bug。
还有一些地方写法感觉复杂了,有时间的话再优化。
看了网上的帖子,对于同样的表名再次写入数据的时候很多都是用remove原表重新写入的方式,这里没有用这个方法。因为考虑到如果是工作中有人用了原本的数据,再次写入时新数据覆盖原数据,会导致调用数据的人源数据异常,所以我这里用的是查重写入的方式。
其实可以不用做查重这一步,数据重复写入可以通过后期清洗处理。这里仅做练习用。
完整代码整理如下:
import time
import random
import re
from urllib import request
from openpyxl import Workbook
from openpyxl import load_workbook
import os
import pymysql
#编写函数获取网页源码
def gethtml(Jobname,StartNum,EndNum):
job = request.quote(request.quote(Jobname)) # 将输入的Jobname参数汉字转码
for i in range(StartNum,EndNum):
time.sleep(random.choice([2,3,4]))
print('正在抓取第',i,'页') # 输出一个小提示,告知在打印第几页
url='https://search.51job.com/list/000000,000000,0000,00,9,99,'+job+',2,'+str(i)\
+'.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99°reefrom=' \
'99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=' \
'-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='
response=request.urlopen(url)
html=response.read().decode('gbk') # 获取网页字符串 html
return html
#编写正则,提取网页内容
def getdata(Jobname,StartNum,EndNum):
allresult=[]
for i in range(StartNum,EndNum):
html=gethtml(Jobname,StartNum,EndNum) # 通过运行源码函数获取html
# 编写正则用来提取信息,去掉的东西都用.*?来代替
reg = re.compile('',re.S)
result=re.findall(reg,html) # 获得一页的内容
allresult+=result # 通过循环,将获得的每一页内容添加到allresult中
return allresult
#存储到excel
def savetoexcel(Jobname,StartNum,EndNum):
data=getdata(Jobname,StartNum,EndNum) # 获取上面爬取的所有数据
#判断文件是否存在
if os.path.exists('51job职位信息.xlsx'):
workbook=load_workbook('51job职位信息.xlsx')
sheetnames = workbook.sheetnames # 获取51job职位信息.xlsx的所有sheet名
#判断sheetname是否存在
if Jobname in sheetnames:
sheet=workbook[Jobname]
values=list(sheet.values) # 获取sheet 的所有内容
non_repeat=list(set(data).difference(set(values))) # 找出data与excel的不重复数据
for each in non_repeat:
sheet.append(each) # 将不重复数据写入
#这里有个小BUG,如果数据里有一个值为空,例:'薪资'为空,则代码不断run出该条数据为不重复数据,会重复写入
else:
sheet=workbook.create_sheet(Jobname)
sheet.append('职位名,公司名,工作地点,薪资,发布时间'.split(','))
for each in data:
sheet.append(each)
else:
workbook=Workbook()
sheet=workbook.active
sheet.title=Jobname
sheet.append('职位名,公司名,工作地点,薪资,发布时间'.split(','))
for each in data:
sheet.append(each)
workbook.save('51job职位信息.xlsx')
#存储到mysql
def savetomysql(Jobname,StartNum,EndNum):
connection = pymysql.connect(
host='localhost',
user='root',
password='1234',
db='jobinfo',
charset='utf8'
)
cursor=connection.cursor()
# 如果数据表不存在,则执行建表,这里表名用的是中文表名
cursor.execute('create table if not exists '+Jobname+\
'(id int(11) primary key auto_increment,' \
'jobname varchar(100) not null,' \
'company varchar(100) not null,' \
'address varchar(50),' \
'salary varchar(50),' \
'ptime varchar(50))' \
'default charset utf8;')
cursor.execute('select jobname,company,address,salary,ptime from '+Jobname)
connection.commit()
all = cursor.fetchall()#获取数据表的数据
length = len(all)#获取数据表的最后一个id
count = 0
data=getdata(Jobname,StartNum,EndNum)# 获取爬取的数据
for each in data:
if each not in all: # 确定要写入的数据不在数据表内
count+=1
sql='insert into '+Jobname+' values '+str((count+length,)+each)+';'
cursor.execute(sql)
connection.commit()
cursor.close()
connection.close()
#这里有个小bug,函数执行时,如果第一次执行和第二次执行,没有更改StartNum,则不会写入新数据
if __name__ == '__main__':
savetoexcel('视频制作',1,3)
savetomysql('运维',2,4)