簡體   English   中英

無法從 Python 中的 POST 接收到所需的結果

[英]Unable to receive desired results from POST in Python

我正在嘗試使用 Requests 從ITC TradeMap獲取數據(我隨機選擇了頁面,所以不要考慮太多)然后清理(還沒有這樣做)並使用 Pandas 導出它,但是我遇到了困難獲取完整的數據集。

import pandas as pd
import requests as rq

#Pandas Settings
pd.set_option("display.max_rows", 999)
pd.set_option("display.max_columns", 999)

#Request Settings
url = 'https://www.trademap.org/Country_SelProductCountry_TS.aspx?nvpm=1%7c643%7c%7c%7c%7c36%7c%7c%7c2%7c1%7c1%7c2%7c2%7c1%7c2%7c1%7c1%7c1'
headers = {
"User-Agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
}
payload = {
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_OutputMode': 'T',
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_PageSizeTab': '300',
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_TS_NumTimePeriod': '10',
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_TS_ReferencePeriod': '2019'
         }

#Output Settings
output_file = 'ITC_Test.xlsx'

#Work
request = rq.post(url, verify=False, headers= headers, data=payload)

table = pd.read_html(request.content)

table[8].to_excel(output_file)

print(table[8])

到目前為止,我正處於測試階段並解決出現的問題(例如,如果在沒有verify = False的情況下請求,它會拋出服務器端ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl .c:997)錯誤),但這不是重點。

我面臨的真正問題是,雖然成功查詢所需的大部分數據都包含在 url 本身中,我會在時間到來時簡單for循環遍歷它,但視圖設置不是,沒有它們我只能檢索 25 行和 5 列數據(過去 5 年的前 25 個貿易伙伴)。

這些設置位於下拉列表 windows 中,它似乎被輸入到as.netForm中,我嘗試使用postdata參數為其提供這些值:

payload = {
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_OutputMode': 'T',
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_PageSizeTab': '300',
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_TS_NumTimePeriod': '10',
            'ctl00$PageContent$GridViewPanelControl$HiddenField_Current_TS_ReferencePeriod': '2019'
         } 

然而,output 似乎沒有受到影響,它仍然只返回 25 行和 5 列的數據,而不是我期望的 300 行和 10 列。

謝謝!

我在這里看到了一些看起來相似的問題,並試圖實現這些想法,但很可能是因為我沒有使用過這些庫,而且我對 Python 的了解一般是相當基礎的,所以我無法解決這些問題,所以任何幫助將非常感激。

謝謝!

我發現了3個問題:

  1. 它必須使用Session()發送 cookies

  2. 它必須發送有效載荷中的所有值 - 所以首先我獲取頁面以從<input><select>獲取所有值

  3. 它在不同的變量中發送新值。

您使用了描述當前 state 的變量,但它發送了名稱為DropDownList的變量

payload['ctl00$PageContent$GridViewPanelControl$DropDownList_NumTimePeriod'] = '20'
payload['ctl00$PageContent$GridViewPanelControl$DropDownList_PageSize'] = '300'

編輯:

我保存了由代碼生成的有效載荷和來自瀏覽器的有效載荷,並使用程序Meld比較文件以查看差異。

我必須更正從<select>獲取值的代碼,因為它需要使用selected搜索<option>

對於某些地址,它需要手動添加一些值,因為通常 JavaScript 會添加這些值

它需要跳過DropDownList_Product_Group


完整的工作代碼:

import pandas as pd
import requests as rq
from bs4 import BeautifulSoup as BS

# hide SSL warnings
from requests.packages.urllib3.exceptions import InsecureRequestWarning
rq.packages.urllib3.disable_warnings(InsecureRequestWarning)

# request settings

#url = 'https://www.trademap.org/Country_SelProduct_TS.aspx?nvpm=1%7c%7c%7c%7c%7c88%7c%7c%7c2%7c1%7c1%7c1%7c2%7c1%7c2%7c1%7c1%7c1'
url = 'https://www.trademap.org/Country_SelProductCountry_TS.aspx?nvpm=1%7c616%7c%7c%7c%7cTOTAL%7c%7c%7c2%7c1%7c1%7c1%7c2%7c1%7c2%7c1%7c%7c1'

print('url:', url.replace('%7c', '|'))

headers = {
    "User-Agent" : "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36"
}

s = rq.Session()

# --- GET ---

print('sending GET ...')

response = s.get(url, verify=False, headers=headers)
    
soup = BS(response.content, 'html.parser')
form = soup.find('form') #.find('div', {'id': 'div_nav_combo'})

payload = {}

#print('--- inputs ---')        
inputs = form.find_all('input')
for item in inputs:# + select:
    name = item.get('name', '')
    #print('name:', name)
    value = item.get('value', '')
    #print('value:', value)

    if name: #and name != 'pg_goal' and 'button' not in name.lower():
        payload[name] = value
        #print(name, '=', value)
    
#print('--- selects ---')        
selects = form.find_all('select')
for item in selects:
    name = item.get('name', '')
    #print('name:', name)
    value = item.get('value', '')
    #print('value:', value)

    if name:
        value = item.find('option', {'selected': True}) or ""
        if value:
            value = value['value']
        payload[name] = value
        #print(name, '=', value)

#print('--- textareas ---')        
#textareas = form.find_all('textarea')
#for item in textareas:
#    name = item.get('name', '')
#    print('name:', name)
#    value = item.get('value', '')
#    print('value:', value)

# --- POST ---

print('sending POST ...')

#payload['ctl00$PageContent$GridViewPanelControl$DropDownList_NumTimePeriod'] = '20'
#payload['__EVENTTARGET'] = 'ctl00$PageContent$GridViewPanelControl$DropDownList_NumTimePeriod'

payload['ctl00$PageContent$GridViewPanelControl$DropDownList_PageSize'] = '300'
#payload['__EVENTTARGET'] = 'ctl00$PageContent$GridViewPanelControl$DropDownList_PageSize'

#payload['ctl00$MenuControl$DDL_Language'] = 'en'

# added by JavaScript
payload['ctl00$NavigationControl$DropDownList_Country_Group'] = '-2'
payload['ctl00$NavigationControl$DropDownList_Partner'] = '-2'
payload['ctl00$NavigationControl$DropDownList_Partner_Group'] = '-2'

# has to remove it for `PageSize` (at least for some addresses)
del payload['ctl00$NavigationControl$DropDownList_Product_Group']
        
response = s.post(url, verify=False, headers=headers, data=payload)

#print(response.content[:1000])

# --- rest ---

# pandas settings
pd.set_option("display.max_rows", 999)
pd.set_option("display.max_columns", 999)

# output settings
output_file = 'ITC_Test.xlsx'

all_tables = pd.read_html(response.content)

table = all_tables[8]

table.to_excel(output_file)

print('len(table):', len(table))
#print(table)

結果:包含 ~230 行和 ~20 列的表格

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM