19

python发起post请求获取json数据使用requests方法

 4 years ago
source link: https://xushanxiang.com/2019/10/python-%e8%8e%b7%e5%8f%96-post-%e5%92%8c-get-%e6%95%b0%e6%8d%ae.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
爬虫过程中,几乎都会遇到post提交方式和get提交方式。传的参数也是有很多方式。现在具体介绍一下post和get区别。

最普通的答案

我一直就觉得GET和POST没有什么除了语义之外的区别,自打我开始学习Web编程开始就是这么理解的 。
可能很多人都已经猜到了答案是:
1.GET 使用URL或Cookie传参。而POST将数据放在BODY中。
2.GET 的 URL 会有长度的限制,则POST的数据则可以非常大。
3.POST比GET安全,因为数据在地址栏上不可见。
但是很不幸,这些区别都是错误的,更不幸的是,这个答案还在Google搜索的头版头条,然而我根本没想到这些是答案,因为在我看来都是错的。我来解释一下。

1.GET 和 POST 与数据如何传参没有关系

GET和POST是由HTTP协议定义的。在HTTP协议中,Method和Data(URL, Body, Header)是正交的两个概念,也就是说,使用哪个Method与应用层的数据如何传输是没有相互关系的。
HTTP没有要求,如果Method是POST数据就要放在BODY中。也没有要求,如果Method是GET,数据(参数)就一定要放在URL中而不能放在BODY中。
那么,网上流传甚广的这个说法是从何而来的呢?我在HTML标准中,找到了相似的描述。这和网上流传的说法一致。但是这只是HTML标准对HTTP协议的用法的约定。怎么能当成GET和POST的区别呢?
而且,现代的Web Server都是支持GET中包含BODY这样的请求。虽然这种请求不可能从浏览器发出,但是现在的Web Server又不是只给浏览器用,已经完全地超出了HTML服务器的范畴了。
知道这个有什么用?我不想解释了,有时候就得自己痛一次才记得住。

2. HTTP协议对GET和POST都没有对长度的限制

HTTP协议明确地指出了,HTTP头和Body都没有长度的要求。而对于URL长度上的限制,有两方面的原因造成:
1.浏览器。据说早期的浏览器会对URL长度做限制。据说IE对URL长度会限制在2048个字符内(流传很广,而且无数同事都表示认同)。但我自己试了一下,我构造了90K的URL通过IE9访问live.com,是正常的。网上的东西,哪怕是Wikipedia上的,也不能信。
2.服务器。URL长了,对服务器处理也是一种负担。原本一个会话就没有多少数据,现在如果有人恶意地构造几个几M大小的URL,并不停地访问你的服务器。服务器的最大并发数显然会下降。另一种攻击方式是,把告诉服务器Content-Length是一个很大的数,然后只给服务器发一点儿数据,嘿嘿,服务器你就傻等着去吧。哪怕你有超时设置,这种故意的次次访问超时也能让服务器吃不了兜着走。有鉴于此,多数服务器出于安全啦、稳定啦方面的考虑,会给URL长度加限制。但是这个限制是针对所有HTTP请求的,与GET、POST没有关系。

好了 关于 GET 和 POST 就说这些。

接下来我们爬取某个网站网站的数据。首先我们分析一些网站的结构,发现该网站使用ajax请求post提交方式 获取数据。

# coding=utf-8
import requests
import json
import time
import re
import datetime
import time
import sys
import math
import shutil
import urlparse
from pyquery import PyQuery as pq
from peewee import *

sys.setrecursionlimit(100000)
reload(sys)
sys.setdefaultencoding('utf8')
str.decode('UTF-8')

#定义全局变量
global city_sx
global city_ids
global city_names
global city_id_sx
global city_time
#河南省城市id
#1郑州 2开封 3洛阳 4安阳 5濮阳 6新乡 7焦作 8三门峡 9鹤壁 10许昌 11漯河 12南阳 13信阳 14济源 15商丘 16周口 17驻马店 18平顶山
city_id_sx = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]
#数据库城市id
#410000 郑州,410200 开封,410300 洛阳,410500 安阳,410900 濮阳,410700 新乡,410800 焦作,411200 三门峡,410600 鹤壁,411000 许昌,411100 漯河,411300 南阳,411500 信阳,410881 济源,
#411400 商丘,411600 周口,411700 驻马店,410400 平顶山
city_ids = [410000, 410200, 410300,410500,410900,410700,410800,411200,410600,411000,411100,411300,411500,410881,411400,411600,411700,410400]
#城市名字
city_names = ['郑州','开封','洛阳','安阳','濮阳','新乡','焦作','三门峡','鹤壁','许昌','漯河','南阳','信阳','济源','商丘','周口','驻马店','平顶山']
#获取13位的时间戳
# current_milli_time = lambda: int(round(time.time() * 1000))
# city_time = current_milli_time()
# print city_time

#链接数据库
database = MySQLDatabase('bxy', **{'host': '$', 'password': '$', 'user': '$', 'use_unicode': True, 'charset': 'utf8', 'port': 3306})


class UnknownField(object):
    def __init__(self, *_, **__): pass


class BaseModel(Model):
    class Meta:
        database = database


class Region(BaseModel):
    name = CharField()
    parent_id = IntegerField(constraints=[SQL("DEFAULT 0")])
    rank = IntegerField(constraints=[SQL("DEFAULT 0")], null=True)

    class Meta:
        table_name = 'region'


class Scens(BaseModel):
    address = CharField(null=True)
    baidu_lat = DecimalField(constraints=[SQL("DEFAULT 0.0000000000")], null=True)
    baidu_lng = DecimalField(constraints=[SQL("DEFAULT 0.0000000000")], null=True)
    business_hours = CharField(null=True)
    characteristic_landscape = TextField(null=True)
    cid = IntegerField()
    cname = CharField()
    consumer_hotline = CharField(null=True)
    interpreter_description = CharField(null=True)
    management_agency = CharField(null=True)
    pid = IntegerField()
    pname = CharField()
    price = CharField(null=True)
    price_description = CharField(null=True)
    scenic_cover = CharField(null=True)
    scenic_introduction = TextField(null=True)
    scenic_level = IntegerField(null=True)
    scenic_site = CharField(null=True)
    scenic_spot_description = CharField(null=True)
    scenic_title = CharField(null=True)
    scenic_type = CharField(null=True)
    sid = AutoField()
    sname = CharField()
    supporting_facilities = TextField(null=True)
    tickets_incentives = TextField(null=True)
    tour_route = TextField(null=True)
    tour_time = CharField(null=True)
    tourist_service_center = TextField(null=True)
    traffic_guide = TextField(null=True)
    xid = IntegerField(constraints=[SQL("DEFAULT 0")], null=True)
    xname = CharField(constraints=[SQL("DEFAULT 'unkown'")], null=True)

    class Meta:
        table_name = 'scens'

#图片处理
def save_img(url):
    file_name = url.split('/')[-1]

    try:
        r = requests.get(url)
    except:
        print('远程连接错误')
        return -1

    try:
        with open(file_name, 'wb') as f:
            f.write(r.content)
    except:
        print('文件保存错误')
        return -1


def upload_img(url):
    import os
    file_name = url.split('/')[-1]

    im = Image.open(file_name)
    w, h = im.size
    # print('Original image size: %sx%s' % (w, h))
    if w > 640:
        im.thumbnail((640, int(math.floor(640.00/w*h))))
        file_name = 'thumbnail.jpg'
        im.save(file_name, 'jpeg')

    # print os.getcwd()
    # os.chdir('%s/scenic_cover' % os.getcwd())
    folder = datetime.datetime.now().strftime('%Y%m/')
    data = {
        'ticket': 'EA8D6730-321B-4B11-9AA2-A925D6E0E91F',
        'dir': folder
    }
    new_file_name = '%s.%s' % (str(uuid.uuid4()), (file_name.split('.')[-1]).lower())
    files = {'myfile': (new_file_name, open(file_name, 'rb'), 'application/octet-stream', {})}
    r = requests.post('127.0.0.1/upload/save_remote', data=data, files=files)
    if r.text == 'true':
        return '%s%s' % (folder, new_file_name)
    else:
        print(r.text)
        return -1
def qs(url):
    query = urlparse.urlparse(url).query
    return dict([(k, urlparse.unquote(v[0])) for k, v in urlparse.parse_qs(query).items()])
#获取城市景区链接数据
def get_city(city_index=0, pg=0, i=0, times=1):
	global city_id_sx, city_names
	#print city_id_sx
	print('\033[0;31m')
	print '当前:city_id:%d, city_name:%s, city_index:%d, pg:%d, index:%d, times:%d' % (city_id_sx[city_index], city_names[city_index], city_index, pg, i, times)
	print('\033[0m')
	print '---------------------->'
	url = 'http://www.uhenan.com/Interface/getData.ashx'
	#请求头
	headers = {
		'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36',
		'Referer':'http://www.uhenan.com/ScenicArea/List?t1=0&t2=1&t3=%200',
		'Host':'www.uhenan.com',
		'Origin':'http://www.uhenan.com',
		'Content-Type': 'application/x-www-form-urlencoded',
		'Cookie':'safedog-flow-item=; __51cke__=; __tins__19387303=%7B%22sid%22%3A%201567134818720%2C%20%22vd%22%3A%202%2C%20%22expires%22%3A%201567137385875%7D; __51laig__=20'
	}
	try:
		#发送post请求
		payload = 'order=desc&field=Top&page=%d&limit=5&method=ScenicArea&Type1=0&Type2=%d&Type3=0&Switch=true&time=' % (city_id_sx[city_index],pg*5)
		print payload
		response = requests.post(url=url, headers=headers, timeout=10,data=payload)
		response.raise_for_status()
	except requests.exceptions.ConnectTimeout:
		print('get_city ConnectTimeout')
		exit(0)
	except requests.exceptions.Timeout:
		print('get_city Timeout')
		exit(0)
	except requests.exceptions.ConnectionError:
		print('get_city ConnectionError')
		exit(0)
	except requests.RequestException as e:
		if requests.status_code == 404:
			print('-' * 20)
			print(' 没有此页。')
			print('-' * 20)
		else:
			print 'get error:', e
			if item > 4:
				exit(0)
			else:
				tiems.sleep(1)
				get_detail(cname, city, id, pg, times+1)
	else:
		#print response.content
		json_obj = json.loads(response.content)
		if len(json_obj['data']) == 0:
			print '<--- end: city_id:%d, city_name:%s' % (city_id_sx[city_index], city_names[city_index])
			if city_index < len(city_id_sx) - 1:
				print '进入下一个市 ===>'
				get_city(city_index+1, 0, 0, 1)
			else:
				print '<=== 本省结束 ===>'
				exit(0)
		for_i = 0
		for item in json_obj['data']:
			if i > for_i:
				for_i = for_i + 1
				continue
			#获取子链接
			#ID        = item['ID']
			#获取景区名字
			Title     = item['Title']
			#获取景区电话
			Phone     = item['Phone']
			#获取景区价格
			Ticket    = item['Ticket']
			str_first = re.sub('<.*?>',"",Ticket)
			str_enfin = str_first.replace('/n',"") 
			#获取景区介绍
			Introduction = item['Introduction']
			str_first = re.sub('<.*?>',"",Introduction)
			str_enfin_1 = str_first.replace(' ', '')
			str_enfin_2 = str_enfin_1.replace(' ', '')
			#获取景区地址
			Address   = item['Address']
			#获取百度坐标
			PointLng  = item['PointLng']
			PointLat  = item['PointLat']
			#获取图片地址:
			Logo      = item['Logo']
			http      = 'http://www.uhenan.com'
			url       = http + Logo
			print Title, str_enfin, Phone, Address, str_enfin_2, PointLng, PointLat, url
			# print city_names[city_index], pg+1, for_i+1, scen_item['ID'], scen_item['Title'],scen_item['Phone'],scen_item['Address'],scen_item['PointLng'],scen_item['PointLat']
			#get_detail(city_names[city_index], city_ids[city_index], ID, pg, 1)
			time.sleep(1)
			for_i = for_i + 1
		get_city(city_index, pg+1, 0, 1)
global city

if __name__ == '__main__':
	city_index = 0
	page = 0
	index = 0

	if len(sys.argv) >= 3:
		city_index = int(sys.argv[1])
	if len(sys.argv) >= 4:
		page = int(sys.argv[2])
	if len(sys.argv) == 5:
		index = int(sys.argv[3])
	get_city(city_index, page, index, 1)

打印结果。

这样关于河南景区的数据获取下来了。


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK