Python模拟登录实战,采集整站表格数据( 二 )


Python模拟登录实战,采集整站表格数据

文章插图
 

Python模拟登录实战,采集整站表格数据

文章插图
 
这三处 。
第一处那里的下一行的csrf_token很明显就是post请求所带的data里的_csrf,另外两个是js里的函数,虽然js没好好学但也能看出来这俩是通过post请求获得州名和县名的,Binggo!一下子解决两个问题 。
为了验证我的猜想,我打算先直接用requests获取点击View Summary前的页面的HTML和cookies,将从HTML中提取的csrf_token值作为点击View Summary时post请求的data里的_csrf值,同时附上cookies,这样两处_csrf就应该是匹配的了:
from lxml import etreeresponse1 = requests.get(url, headers=headers)cookies = response1.cookieshtml = etree.HTML(response1.text)csrf_token = html.xpath('/html/head/meta[3]/@content')[0]data.update({'_csrf': csrf_token})response2 = requests.post(url, data=https://www.isolves.com/it/cxkf/yy/Python/2020-08-19/data, headers=headers, cookies=cookies)print(response2.status_code)输出200,虽然和Chrome显示的302不一样,但是也表示成功,那就不管了 。把response2.text写入html文件打开看是这样:
Python模拟登录实战,采集整站表格数据

文章插图
 
Yeah,数据都在!说明我的猜想是对的!那一会再试试我从没用过的requests.Session()维持会话,自动处理cookies 。
尝试pandas库提取网页表格现在既然已经拿到了目标页面的HTML,那在获取所有年、地区、州名、县名之前,先测试一下pandas.read_html提取网页表格的功能 。
pandas.read_html这个函数时在写代码时IDE自动补全下拉列表里瞄到的,一直想试试来着,今天乘机拉出来溜溜:
import pandas as pddf = pd.read_html(response2.text)[0]print(df)输出:
Python模拟登录实战,采集整站表格数据

文章插图
 
Yeah!拿到了,确实比自己手写提取方便,而且数值字符串自动转成数值,优秀!
准备所有参数接下来要获取所有年、地区、州名、县名 。年份和地区是写死在HTML里的,直接xpath获取:
Python模拟登录实战,采集整站表格数据

文章插图
 
州名、县名根据之前发现的两个js函数,要用post请求来获得,其中州名要根据地区名获取,县名要根据州名获取,套两层循环就行
def new():    session = requests.Session()    response = session.get(url=url, headers=headers)    html = etree.HTML(response.text)    return session, html session, html = new()years = html.xpath('//*[@id="crmsearchform-year"]/option/text()')regions = html.xpath('//*[@id="crmsearchform-region"]/option/text()')_csrf = html.xpath('/html/head/meta[3]/@content')[0]region_state = {}state_county = {}for region in regions:    data = https://www.isolves.com/it/cxkf/yy/Python/2020-08-19/{'region': region, '_csrf': _csrf} response = session.post(url_state, data=data) html = etree.HTML(response.json()) region_state[region] = {x: y for x, y in zip(html.xpath('//option/@value'), html.xpath('//option/text()'))} for state in region_state[region]: data = {'state': state, '_csrf': _csrf} response = session.post(url_county, data=data) html = etree.HTML(response.json()) state_county[state] = html.xpath('//option/@value')啧啧,使用requests.Session就完全不需要自己管理cookies了,方便!具体获得的州名县名就不放出来了,实在太多了 。然后把所有年、地区、州名、县名的可能组合先整理成csv文件,一会直接从csv里读取并构造post请求的data字典:
remain = [[str(year), str(region), str(state), str(county)]         for year in years for region in regions         for state in region_state[region] for county in state_county[state]]remain = pd.DataFrame(remain, columns=['CRMSearchForm[year]',                                       'CRMSearchForm[region]',                                       'CRMSearchForm[state]',                                       'CRMSearchForm[county]'])remain.to_csv('remain.csv', index=False)# 由于州名有缩写和全称,也本地保存一份import jsonwith open('region_state.json', 'w') as json_file:        json.dump(region_state, json_file, indent=4)


推荐阅读