本次工具主要利用python easygui模块的inputbox让用户首次输入登陆信息,作为网站requests-post请求的data字段,观察XHR(异步加载)的数据包,构造post请求,利用requests库的session功能保持登陆状态,进而请求其他子页下的所需信息,最终爬取到本地excel文件中。

我们手工登陆后,网站会进行跳转,通过浏览器F12查看network页签,logindo页面可以看到登陆后服务器在response headers栏 有set-cookie:

python 保持json python 保持session_openpyxl

 

但是网站登陆redirect后的页面并没有看到:response.cookies;

 

python 保持json python 保持session_session_02

如果利用response.cookies将得到一个空的RequestsCookieJar对象,无法为后续的信息爬取提供cookies字段放入headers栏,此时可以考虑用response.session保持首次登陆状态,后续服务器端在session有效期内不会再要求页面传入登陆信息,主要代码如下,:

import requests,json,easygui,os,sys,math,time
from openpyxl import load_workbook
msg = "请输入OA用户名和密码"
title = "用户登录入口"
user_info = []
user_info = easygui.multpasswordbox(msg,title,("用户名","密码"))
start = time.time()
pwd = os.getcwd()

wb = load_workbook(filename=pwd+u"\\info_list.xlsx")
sheet=wb[u"参数"]

base_url='http://******.com/srm/supplier/Criteria.do'

loginData={'redirect':'','username':user_info[0],'password':user_info[1]}
#下面的data-search字典中,condition键其实就是Oracle数据库的select条件在网页中的集成形式,通过设置exp表达式以及value等,可以灵活的查询,突破页面集成的查询默认条件限制。
data_search={
    'page':1,#控制请求的页面数
    'rows':100,#控制每页显示的行数
    'condition':'[{"orConditionList":[{"column":"S.S_SUPPLIER_NO","exp":"like","value":"00001"}]},{"column":"S.S_SUPPLIER_NO","orderType":"default","orderKey":"","direction":"DESC"}]',
    'additionalParams':'{}'
}
s=requests.session()
def login(s,loginData,data_search):
    try:       
        response=s.post('http://******.com/portal/u/a/login.do',loginData)       
        if response.status_code==200:
            print("login_success")   
    except requests.ConnectionError as e:
        print('Error',e.args)   
def getjson(s,base_url,data_search):
    try:
        response=s.post(base_url,data_search)
        if response.status_code==200:
            #print("vendor_info_yes")
            return response.json()
    except requests.ConnectionError as e:
        print('Error',e.args)

if __name__ == "__main__":
    ss=login(s,loginData,data_search)
    page=getjson(s,base_url,data_search)

    maxNum=math.ceil(page['total']/100)   #计算出总的信息显示所需页面数
    for pageNum in range(1,500):
        if pageNum==maxNum+1:
            wb.save(filename=pwd+u"\\info_list.xlsx") #最后一页写完后,进行保存excel操作
            end = time.time()
            time.sleep(2)
            sys.exit(0)
        data_search['page']=pageNum #修改字典的‘page’键对应值,逐页请求服务器数据
        page=getjson(s,base_url,data_search)
        listlen=len(page['rows']) #由于最后一次得到的行数不见得是100行,所以需要动态获取列表长度,作为循环次数的依据。
        for i in range(listlen):  #对请求后得到的json文件进行解析,类似于字典,字典中含有列表,需要注意,当部分字段为空时,字典中部分元素可能不存在,需要判断字典。

            sheet['A%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['supplierNo']
            sheet['B%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['companyName']
            if 'linkMan1' in page['rows'][i].keys():
                sheet['C%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['linkMan1']
            if 'phone1' in page['rows'][i].keys():                
                sheet['D%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['phone1']
            if 'email1' in page['rows'][i].keys():      
                sheet['E%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['email1']
            if 'legalRepresentative' in page['rows'][i].keys():                 
                sheet['F%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['legalRepresentative']
            if 'email2' in page['rows'][i].keys():
                sheet['G%d' %((pageNum-1)*100+i+2)].value = page['rows'][i]['email2']
        print(pageNum)

 

该程序还有一个可以完善的地方:就是封装后给用户使用时不够直观,需要利用Tkinter等制作简易gui进度条百分比及剩余时间展示。