最普通的答案
我一直就觉得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提交方式 获取数据。
1 # coding=utf-8 2 import requests 3 import json 4 import time 5 import re 6 import datetime 7 import time 8 import sys 9 import math 10 import shutil 11 import urlparse 12 from pyquery import PyQuery as pq 13 from peewee import * 14 15 sys.setrecursionlimit(100000) 16 reload(sys) 17 sys.setdefaultencoding('utf8') 18 str.decode('UTF-8') 19 20 #定义全局变量 21 global city_sx 22 global city_ids 23 global city_names 24 global city_id_sx 25 global city_time 26 #河南省城市id 27 #1郑州 2开封 3洛阳 4安阳 5濮阳 6新乡 7焦作 8三门峡 9鹤壁 10许昌 11漯河 12南阳 13信阳 14济源 15商丘 16周口 17驻马店 18平顶山 28 city_id_sx = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18] 29 #数据库城市id 30 #410000 郑州,410200 开封,410300 洛阳,410500 安阳,410900 濮阳,410700 新乡,410800 焦作,411200 三门峡,410600 鹤壁,411000 许昌,411100 漯河,411300 南阳,411500 信阳,410881 济源, 31 #411400 商丘,411600 周口,411700 驻马店,410400 平顶山 32 city_ids = [410000, 410200, 410300,410500,410900,410700,410800,411200,410600,411000,411100,411300,411500,410881,411400,411600,411700,410400] 33 #城市名字 34 city_names = ['郑州','开封','洛阳','安阳','濮阳','新乡','焦作','三门峡','鹤壁','许昌','漯河','南阳','信阳','济源','商丘','周口','驻马店','平顶山'] 35 #获取13位的时间戳 36 # current_milli_time = lambda: int(round(time.time() * 1000)) 37 # city_time = current_milli_time() 38 # print city_time 39 40 #链接数据库 41 database = MySQLDatabase('bxy', **{'host': '$', 'password': '$', 'user': '$', 'use_unicode': True, 'charset': 'utf8', 'port': 3306}) 42 43 44 class UnknownField(object): 45 def __init__(self, *_, **__): pass 46 47 48 class BaseModel(Model): 49 class Meta: 50 database = database 51 52 53 class Region(BaseModel): 54 name = CharField() 55 parent_id = IntegerField(constraints=[SQL("DEFAULT 0")]) 56 rank = IntegerField(constraints=[SQL("DEFAULT 0")], null=True) 57 58 class Meta: 59 table_name = 'region' 60 61 62 class Scens(BaseModel): 63 address = CharField(null=True) 64 baidu_lat = DecimalField(constraints=[SQL("DEFAULT 0.0000000000")], null=True) 65 baidu_lng = DecimalField(constraints=[SQL("DEFAULT 0.0000000000")], null=True) 66 business_hours = CharField(null=True) 67 characteristic_landscape = TextField(null=True) 68 cid = IntegerField() 69 cname = CharField() 70 consumer_hotline = CharField(null=True) 71 interpreter_description = CharField(null=True) 72 management_agency = CharField(null=True) 73 pid = IntegerField() 74 pname = CharField() 75 price = CharField(null=True) 76 price_description = CharField(null=True) 77 scenic_cover = CharField(null=True) 78 scenic_introduction = TextField(null=True) 79 scenic_level = IntegerField(null=True) 80 scenic_site = CharField(null=True) 81 scenic_spot_description = CharField(null=True) 82 scenic_title = CharField(null=True) 83 scenic_type = CharField(null=True) 84 sid = AutoField() 85 sname = CharField() 86 supporting_facilities = TextField(null=True) 87 tickets_incentives = TextField(null=True) 88 tour_route = TextField(null=True) 89 tour_time = CharField(null=True) 90 tourist_service_center = TextField(null=True) 91 traffic_guide = TextField(null=True) 92 xid = IntegerField(constraints=[SQL("DEFAULT 0")], null=True) 93 xname = CharField(constraints=[SQL("DEFAULT 'unkown'")], null=True) 94 95 class Meta: 96 table_name = 'scens' 97 98 #图片处理 99 def save_img(url): 100 file_name = url.split('/')[-1] 101 102 try: 103 r = requests.get(url) 104 except: 105 print('远程连接错误') 106 return -1 107 108 try: 109 with open(file_name, 'wb') as f: 110 f.write(r.content) 111 except: 112 print('文件保存错误') 113 return -1 114 115 116 def upload_img(url): 117 import os 118 file_name = url.split('/')[-1] 119 120 im = Image.open(file_name) 121 w, h = im.size 122 # print('Original image size: %sx%s' % (w, h)) 123 if w > 640: 124 im.thumbnail((640, int(math.floor(640.00/w*h)))) 125 file_name = 'thumbnail.jpg' 126 im.save(file_name, 'jpeg') 127 128 # print os.getcwd() 129 # os.chdir('%s/scenic_cover' % os.getcwd()) 130 folder = datetime.datetime.now().strftime('%Y%m/') 131 data = { 132 'ticket': 'EA8D6730-321B-4B11-9AA2-A925D6E0E91F', 133 'dir': folder 134 } 135 new_file_name = '%s.%s' % (str(uuid.uuid4()), (file_name.split('.')[-1]).lower()) 136 files = {'myfile': (new_file_name, open(file_name, 'rb'), 'application/octet-stream', {})} 137 r = requests.post('127.0.0.1/upload/save_remote', data=data, files=files) 138 if r.text == 'true': 139 return '%s%s' % (folder, new_file_name) 140 else: 141 print(r.text) 142 return -1 143 def qs(url): 144 query = urlparse.urlparse(url).query 145 return dict([(k, urlparse.unquote(v[0])) for k, v in urlparse.parse_qs(query).items()]) 146 #获取城市景区链接数据 147 def get_city(city_index=0, pg=0, i=0, times=1): 148 global city_id_sx, city_names 149 #print city_id_sx 150 print('