如何以正确的方式使用POST请求?

时间:2017-12-09 05:59:28

标签: python python-3.x web-scraping beautifulsoup http-post

我已经编写了一些代码来从网页中获取数据。该网站有下拉选项来选择首选项目。因此,首先我发出GET请求以形成网址,然后发出POST请求。我设法仅从其首页解析数据,但填充的结果显示在多个页面上。当我更改表单数据参数中的页码时,它对结果没有任何影响。我仍然从第一页得到结果。我怎么能得到它们?顺便说一句,根据我的偏好,我没有从下拉选项中选择任何东西;相反,我发起了搜索默认偏好设置的方式。

指向该网站的链接:URL

这是我迄今为止所尝试过的:

import requests
from bs4 import BeautifulSoup

payload={

    's':'opportunity',
    'mode':'list',
    'tab':'list',
    'pageID':3
}

r = requests.get("replace_with_above_url",params=payload,headers={'User-Agent':'Mozilla/5.0'})

payload={

    'dnf_class_values[procurement_notice][_posted_date]':'90',
    'dnf_class_values[procurement_notice][set_aside][]':'',
    'dnf_class_values[procurement_notice][zipstate]':'',
    'dnf_class_values[procurement_notice][procurement_type][]':'',
    'dnf_class_values[procurement_notice][keywords]':'',
    'autocomplete_input_dnf_class_values[procurement_notice][agency]':'',
    'dnf_class_values[procurement_notice][agency]':'',
    'so_form_prefix':'dnf_',
    'dnf_opt_action':'search',
    'dnf_opt_template':'vendor_procurement_notice_filter',
    'dnf_opt_mode':'update',
    'dnf_opt_finalize':'0',
    'dnf_opt_target':'',
    'dnf_opt_validate':'1',
    'dnf_class_values[procurement_notice][dnf_class_name]':'procurement_notice',
    'clear_filters_from_home':'1'   
}

res = requests.post(r.url,data=payload, headers={'User-Agent':'Mozilla/5.0'})
soup = BeautifulSoup(res.text,"lxml")
for item in soup.select(".solt"):
    print(item.text)

2 个答案:

答案 0 :(得分:1)

通过Web控制台检查网站显示,按下搜索按钮会发出一个带有查询字符串和表单数据参数的POST请求,同时单击下面的页面锚点,启动GET请求,仅使用查询字符串(和pageID参数集)相应地)。

我编辑了你的代码,添加了一个run函数,它将页面ID作为page参数,如果page等于1则发出POST,否则发出GET:

import requests
from bs4 import BeautifulSoup

payload={

    'dnf_class_values[procurement_notice][_posted_date]':'90',
    'dnf_class_values[procurement_notice][set_aside][]':'',
    'dnf_class_values[procurement_notice][zipstate]':'',
    'dnf_class_values[procurement_notice][procurement_type][]':'',
    'dnf_class_values[procurement_notice][keywords]':'',
    'autocomplete_input_dnf_class_values[procurement_notice][agency]':'',
    'dnf_class_values[procurement_notice][agency]':'',
    'so_form_prefix':'dnf_',
    'dnf_opt_action':'search',
    'dnf_opt_template':'vendor_procurement_notice_filter',
    'dnf_opt_mode':'update',
    'dnf_opt_finalize':'0',
    'dnf_opt_target':'',
    'dnf_opt_validate':'1',
    'dnf_class_values[procurement_notice][dnf_class_name]':'procurement_notice',
    'clear_filters_from_home':'1',
}
def run(page):
    url = "the given url"
    query = {
        's': 'opportunity',
        'mode': 'list',
        'tab': 'list',
        'pageID': page
    }
    if(page==1):
        r = requests.get(url, params=query, headers={'User-Agent': 'Mozilla/5.0'})
        res = requests.post(r.url,data=payload, headers={'User-Agent':'Mozilla/5.0'})
    else:
        res = requests.get(url, params=query, headers={'User-Agent': 'Mozilla/5.0'})
    soup = BeautifulSoup(res.text,"lxml")
    for item in soup.select(".solt"):
        print(item.text)

for page in range(10):
    run(page + 1)

此代码可生成200行,即10页,每页20个结果。

答案 1 :(得分:0)

服务器使用会话cookie “记住”您的搜索。您的代码会丢弃服务器返回的所有cookie,因此每次发出新请求时都会重置内存。

使用session object记录传入的Cookie,并在随后的请求中将其再次发送出去:

with requests.Session() as sess:
    sess.headers['User-Agent'] = 'Mozilla/5.0'
    r = sess.get("replace_with_above_url", params=payload)

    # ...

    res = sess.post(r.url, data=payload)

然后,您可以使用从GET开始的数字页面ID提交/index?s=opportunity&mode=list&tab=list&pageID=1个网址请求,直到您遇到空结果集:

page_id = 0
page_url = 'https://www.fbo.gov/index?s=opportunity&mode=list&tab=list&pageID={}'
while True:
    page_id += 1 
    page = sess.get(page_url.format(page_id))
    soup = BeautifulSoup(page.text, "lxml")
    rows = soup.select('.solr-lst table tr')
    if len(rows) <= 1:
        break
    for row in rows[1:]:
        print([c.get_text(strip=True) for c in rows[1].select('td')])