1、首先有一个账号的excel文件,里面包含企业名称、登录账号以及登录密码;
2、获取账号文件里面的信息,实现模拟登录,登录成功则获取运费,登录失败则提示并且将失败的手机号颜色标红;
3、后台网站用XXXX代替。
#!/usr/bin/env python
# coding=utf-8
# 获取后台系统的运费规则,保存到表格中,其中登录账号从本地表格中获取
# 增加了退出账号功能和多次尝试登录的功能,以免第一次因网络波动尝试失败
import requests
from bs4 import BeautifulSoup
from lxml import etree
from openpyxl import Workbook
import os,re,time
from fileread import ProcessData
from convert import Convert
class CBS_crawl(object):
def __init__(self, username, password):
# 初始化headers实例
self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0",
"Referer": "https://cbs.XXXX.com/login.html"
}
# 核实界面
self.post_url = "https://cbs.XXXX.com/j_spring_security_check"
# session会话对象
self.session = requests.session()
self.username = username
self.password = password
self.data = ['入驻企业名称','运费内容','运费区域']
self.wb = Workbook()
self.datavalue = []
self.session.keep_alive = False
# 提取表单登录信息(可以和模拟登陆合并成一个)
def get_login_info(self):
data = {
"j_username": self.username,
"j_password": self.password
}
return data
# 模拟登录
def login(self):
print("模拟登录。。。")
data = self.get_login_info()
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0",
"Referer": self.post_url,
"X-Requested-With": "XMLHttpRequest"
}
# 循环操作的目的是防止网络连接不稳定导致出现错误:HTTPSConnectionPool[WinError 10060]、[Errno 11004]等
# 如果出错就重复尝试登录,这里设置的三次
maxTryNum = 4
for tries in range(maxTryNum):
try:
time.sleep(2)
login_page = self.session.post(self.post_url, data=data, headers=headers)
time.sleep(2)
# print(login_page.text)
if "errorMsg" in login_page.text:
print("登录失败,错误的手机号码或密码!")
# 将登录失败的手机号添加到一个列表中,颜色变为红色
fail_phone = []
fail_phone.append(self.username)
ProcessData().fail_high_light(fail_phone)
break
if "</span>首页" in login_page.text:
print("欢迎您'%s',成功登陆CBS管理系统!"%self.username)
# 登录成功的手机号码添加到列表中,颜色变为黑色,考虑之前登录失败后来登录成功的情况
success_phone = []
success_phone.append(self.username)
ProcessData().success_high_light(success_phone)
company_name = self.freight_on_list()
# 获取完数据后退出后台
time.sleep(2)
self.quit_on_list(company_name)
# 只要有登录成功的手机号,最后才会去调用合并功能
return len(success_phone)
except Exception as e:
if tries < (maxTryNum-1):
print("出错了,重新尝试第%d次中,问题为:%s"%(tries+1,e))
continue
else:
print("重新尝试次数超过限制",e)
break
# print("登陆成功!")
# 退出系统
def quit_on_list(self,company_name):
quit_url = 'https://cbs.XXXX.com/j_spring_security_logout'
print("退出该账号:%s"%company_name[0].strip())
self.session.post(quit_url, headers=self.headers)
time.sleep(2)
#获取运费的信息
def freight_on_list(self):
# 系统设置网址,获取商家名字
company_url = "https://cbs.XXXX.com/system/companyshow.html"
# 注意company_list返回的是一个response对象,需加.text才能显示具体网页内容
company_list = self.session.post(company_url, headers=self.headers)
company_html = etree.HTML(company_list.text)
# 获取商家名称,首尾有空格
company_name = company_html.xpath("//div[@id='tabs-1']/p[1]/span/text()")
# 运费网址
freight_list_url = "https://cbs.XXXX.com/shipfee/shipfeesupfee.html"
freight_list = self.session.post(freight_list_url, headers=self.headers)
# 利用xpath规则提取运费的ID、运费内容等信息
html = etree.HTML(freight_list.text)
# 提取运费id号,如果有那么freight_id长度为2,没有长度为1
freight_id = html.xpath('//div/form[@id="shipfeeForm"]/input/@value')
# 运费内容,可能会有多个情况
freight_content = html.xpath('//table[@class="stdtable"]/tbody/tr/td[2]/text()')
# 运费区域
freight_area = html.xpath('//table[@class="stdtable"]/tbody/tr/td[3]/text()')
# 获取模板类型
patt = re.compile(r'checked="checked" value="(\d+)"')
# 如果结果是1代表全国统一计费,如果是2代表按区域计费,str类型
mould_type = patt.search(freight_list.content.decode('utf-8')).group(1)
# 肯定有运费内容情况
if len(freight_content) != 0:
for i in range(len(freight_content)):
# 有运费id,有运费内容
if len(freight_id) == 2:
if mould_type == '1':
freight_content = freight_content
# 只有这种情况下,才有可能出现,多个运费条款,一个全国区域的情况,为了列表长度统一,所以乘
freight_area = ["模板类型:全国统一计费,运费区域全国"]*len(freight_content)
elif mould_type == '2':
freight_area = freight_area
freight_content = freight_content
# 无运费情况
else:
# 有id,无运费
if len(freight_id) == 2:
freight_content = ["运费添加过,但是没有运费条款,默认包邮"]
freight_area = ["运费添加过,但是没有运费条款,区域全国"]
# 无id,无运费
else:
freight_content = ["从未设置过运费,默认包邮"]
freight_area = ["从未设置过运费,区域全国"]
# 处理运费内容到临时文件夹的表格中
self.save_content(company_name,freight_content,freight_area)
return company_name
def save_content(self,company_name,freight_content,freight_area):
# company_name是列表并且只有一个值,所以是0,并去除首尾空格
print("'%s'运费处理中...."%company_name[0].strip())
# 如果有多个运费,那么企业名称也相应的有多个,方便写入
company_name_list = company_name*(len(freight_content))
ws = self.wb.active
ws.title = '运费规则' # 修改第一个sheet表名
# 先写入表头
for head in range(1,len(self.data)+1):
ws.cell(row = 1,column=head,value=self.data[head-1])
# 从第2行开始以后写入N行1列企业名称
for i in range(2,len(freight_content)+2):
ws.cell(row =i ,column = 1,value=company_name_list[i-2].strip())
# 从第2行开始以后写入N行2列运费规则
for i in range(2,len(freight_content)+2):
ws.cell(row =i ,column = 2,value=freight_content[i-2])
# 从第2行开始以后写入N行3列运费区域
for j in range(2,len(freight_area)+2):
ws.cell(row =j ,column = 3,value=freight_area[j-2])
# 创建临时文件夹,如果不存在则创建,存在则不创建
if not os.path.exists('./临时文件'):
os.makedirs('./临时文件')
# 隐藏文件夹,不能隐藏否则搜索不到,只能合并完最后删除掉此文件夹
# os.popen('attrib +h ' + './临时文件')
# 临时文件夹中的文件命名
file = './临时文件/' + company_name[0].strip() +"-运费规则.xlsx"
self.wb.save(file)
print("以上数据处理完毕!")
if __name__ == "__main__":
try:
data_dict = ProcessData().getData()
# print(data_dict)
# 将符合要求的11位手机号和不是空的密码存入新字典
new_data_dict = {}
for key, value in data_dict.items():
if len(key) == 11:
if value != 'None':
new_data_dict[key] = value
else:
print("\n"+"账号'%s'此行密码不能为空,请核实账号表格!" % key)
ProcessData().fail_high_light(key)
elif key != 'None' and len(key) !=11:
print("\n"+"账号'%s'此行手机号码输入有误,请核实!"%key)
ProcessData().fail_high_light(key)
else:
print("\n"+"手机号码有空值,请核实!")
if new_data_dict:
count = 0
for key, value in new_data_dict.items():
username = key
password = value
print("\n"+"尝试登录账号'%s'中..." % (username))
az = CBS_crawl(username, password)
count = az.login()
time.sleep(2)
# 调用convert文件的main模块,实现合并文件,只有有登录成功的号码才会去调用合并功能
if count:
Convert().main()
else:
# 如果没有一个登录成功的账号,返回提示
print("\n" + "抱歉,以上均没有符合条件的登录账号,请核实账号表格!")
else:
print("\n"+"抱歉,以上均没有符合条件的登录账号,请核实账号表格!")
input('\n'+'请按回车键退出!') # 目的执行.bat脚本的时候窗口不会闪退
except Exception as e:
print("出错了,问题为:",e)
input('\n'+'请按回车键退出!') # 目的执行.bat脚本的时候窗口不会闪退
#!/usr/bin/env python
# coding=utf-8
# 这里面处理并获取账号信息,以及将登录失败的手机号标颜色
import openpyxl
from openpyxl.styles import colors
from openpyxl.styles import Font
class ProcessData(object):
def __init__(self):
self.file_name = "./账号.xlsx"
self.wb = openpyxl.load_workbook(self.file_name)
self.sheet = self.wb.worksheets[0]
# try:
# self.file_name = "./账号.xlsx"
# self.wb = openpyxl.load_workbook(self.file_name)
# self.sheet = self.wb.worksheets[0]
# except Exception as e:
# print("错误,问题为:",e)
# 获取账号信息
def getData(self):
# 将来是字典的key值
self.data_list_keys = []
# 将来是字典的values值
data_list_values = []
data_dict = {}
# 获取B列账号信息
for cellobj_keys in self.sheet['B']:
self.data_list_keys.append(cellobj_keys.value)
# 获取D列密码信息
for cellobj_values in self.sheet['D']:
data_list_values.append(cellobj_values.value)
# 组合成字典,去掉第一行
for i in range(1,len(data_list_values)):
data_dict[str(self.data_list_keys[i])] = str(data_list_values[i])
# print(data_dict.items())
# for key in data_dict.keys():
# username = key
# password = value
# print("尝试登录账号'%s'中..."%(username))
return (data_dict)
# 登录失败电话号码颜色为红色
def fail_high_light(self,fail_phone):
for cell in self.sheet['B']:
# cell.value如果是手机号这里是int类型,而fail_phone是列表,里面是str类型
if str(cell.value) in fail_phone:
print("无法登陆账号,颜色处理中...")
cell.font = Font(color=colors.RED)
# 将第一行第二列的登录账号加粗
self.sheet.cell(1,2).font = Font(bold=True)
self.wb.save(self.file_name)
# 如果登录成功,电话号码颜色变黑,考虑之前登录失败后来登录成功的情况
def success_high_light(self,success_phone):
for cell in self.sheet['B']:
# cell.value如果是手机号这里是int类型,而success_phone是列表,里面是str类型
if str(cell.value) in success_phone:
cell.font = Font(color=colors.BLACK)
# 将第一行第二列的登录账号加粗
self.sheet.cell(1,2).font = Font(bold=True)
self.wb.save(self.file_name)
#!/usr/bin/env python
# coding=utf-8
# 对生成的多个临时文件进行合并,最后删除临时文件夹
from openpyxl import Workbook
import os,shutil,time,xlrd,xlsxwriter
import glob
class Convert(object):
def __init__(self):
# 在哪里搜索多个表格
self.filelocation = "./临时文件"
self.datavalue = []
self.data = ['入驻企业名称', '运费内容', '运费区域']
if not os.path.exists(self.filelocation):
print('未找到指定目录,系统已自动创建,请将需要合并的文件放到该目录下,目录为:%s' % self.filelocation)
os.makedirs(self.filelocation)
# else:
# self.main()
def main(self):
# 当前文件夹下搜索的文件名后缀
f_list = os.listdir(self.filelocation)
# print(f_list)
end_file = []
for i in f_list:
# os.path.splitext():分离文件名与扩展名
if os.path.splitext(i)[1] == '.xlsx':
j = os.path.splitext(i)[1]
# print(j) #.xlsx
# print(os.path.splitext(i)[1])
end_file.append(j)
# fileform = ".xlsx"
# 首先查找默认文件夹下有多少文档需要整合
# print(end_file)
filearray = [] #最终需要的.xlsx文件的列表
for fileform in set(end_file): # end_file里面包含多个.xlsx内容,只需要一个即可
for filename in glob.glob(self.filelocation +"/"+ "*" + fileform):
filearray.append(filename)
# print(filearray)
for i in range(len(filearray)):
end_file = self.hebing(filearray[i])
print("\n"+"数据合并中.....")
# 删除临时文件
self.del_file()
address = os.path.abspath(end_file)
print("数据合并完成,保存在'%s'"%address)
# 将数据合并到一个文件中
def hebing(self, file):
fh = self.open_xls(file)
x = self.getshnum(fh)
rvalue=[]
for shnum in range(x):
rvalue = self.getFilect(shnum, fh) # 生成最终数据列表嵌套[[],[],[],[]]
# 当天的日期
file_name_date = time.strftime("%Y-%m-%d", time.localtime())
endfile = './运费规则总表' + file_name_date + '.xlsx'
wb1 = xlsxwriter.Workbook(endfile) # 建立文件
# 创建一个sheet工作对象
ws = wb1.add_worksheet('运费规则') # 建立sheet
# 要先写表头,占了第一行,所以下面应该从第二行开始添加
for i in range(0, len(self.data)):
ws.write(0, i, self.data[i]) # 写入0行i列数据
for a in range(len(rvalue)):
for b in range(len(rvalue[a])):
c = rvalue[a][b]
# 要a+1行,第一行被表头占据
ws.write(a + 1, b, c)
wb1.close()
return endfile
# 打开一个excel文件
def open_xls(self, file):
fh = xlrd.open_workbook(file)
return fh
# 获取sheet表的个数
def getshnum(self, fh):
x = 0
sh = self.getsheet(fh)
for sheet in sh:
x += 1
return x
# 获取excel中所有的sheet表
def getsheet(self, fh):
return fh.sheets()
def getFilect(self, shnum, fh): # shnum第几个sheet表,第一个值是0
table = fh.sheets()[shnum]
num = table.nrows # sheet表有多少行数据
for row in range(1, num): # 从1开始不会读取每个表格的表头,从0开始或者不填就会
rdata = table.row_values(row)
# 需要判断这一行是不是空行,如果是空行则不添加
rdata = [str(i) for i in rdata] # 将内容全部转换为字符串
if ''.join(rdata) != '': # 如果不为空则添加到datavalue列表里
self.datavalue.append(rdata)
return self.datavalue
# 删除临时文件
def del_file(self):
# 删除临时文件夹和里面生成的文件
shutil.rmtree(self.filelocation)