最普通的答案
我一直就覺得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('\033[0;31m') 151 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) 152 print('\033[0m') 153 print '---------------------->' 154 url = 'http://www.uhenan.com/Interface/getData.ashx' 155 #請求頭 156 headers = { 157 'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36', 158 'Referer':'http://www.uhenan.com/ScenicArea/List?t1=0&t2=1&t3=%200', 159 'Host':'www.uhenan.com', 160 'Origin':'http://www.uhenan.com', 161 'Content-Type': 'application/x-www-form-urlencoded', 162 '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' 163 } 164 try: 165 #發送post請求 166 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) 167 print payload 168 response = requests.post(url=url, headers=headers, timeout=10,data=payload) 169 response.raise_for_status() 170 except requests.exceptions.ConnectTimeout: 171 print('get_city ConnectTimeout') 172 exit(0) 173 except requests.exceptions.Timeout: 174 print('get_city Timeout') 175 exit(0) 176 except requests.exceptions.ConnectionError: 177 print('get_city ConnectionError') 178 exit(0) 179 except requests.RequestException as e: 180 if requests.status_code == 404: 181 print('-' * 20) 182 print(' 沒有此頁。') 183 print('-' * 20) 184 else: 185 print 'get error:', e 186 if item > 4: 187 exit(0) 188 else: 189 tiems.sleep(1) 190 get_detail(cname, city, id, pg, times+1) 191 else: 192 #print response.content 193 json_obj = json.loads(response.content) 194 if len(json_obj['data']) == 0: 195 print '<--- end: city_id:%d, city_name:%s' % (city_id_sx[city_index], city_names[city_index]) 196 if city_index < len(city_id_sx) - 1: 197 print '進入下一個市 ===>' 198 get_city(city_index+1, 0, 0, 1) 199 else: 200 print '<=== 本省結束 ===>' 201 exit(0) 202 for_i = 0 203 for item in json_obj['data']: 204 if i > for_i: 205 for_i = for_i + 1 206 continue 207 #獲取子鏈接 208 #ID = item['ID'] 209 #獲取景區名字 210 Title = item['Title'] 211 #獲取景區電話 212 Phone = item['Phone'] 213 #獲取景區價格 214 Ticket = item['Ticket'] 215 str_first = re.sub('<.*?>',"",Ticket) 216 str_enfin = str_first.replace('/n',"") 217 #獲取景區介紹 218 Introduction = item['Introduction'] 219 str_first = re.sub('<.*?>',"",Introduction) 220 str_enfin_1 = str_first.replace(' ', '') 221 str_enfin_2 = str_enfin_1.replace(' ', '') 222 #獲取景區地址 223 Address = item['Address'] 224 #獲取百度坐標 225 PointLng = item['PointLng'] 226 PointLat = item['PointLat'] 227 #獲取圖片地址: 228 Logo = item['Logo'] 229 http = 'http://www.uhenan.com' 230 url = http + Logo 231 print Title, str_enfin, Phone, Address, str_enfin_2, PointLng, PointLat, url 232 # 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'] 233 #get_detail(city_names[city_index], city_ids[city_index], ID, pg, 1) 234 time.sleep(1) 235 for_i = for_i + 1 236 get_city(city_index, pg+1, 0, 1) 237 global city 238 239 if __name__ == '__main__': 240 city_index = 0 241 page = 0 242 index = 0 243 244 if len(sys.argv) >= 3: 245 city_index = int(sys.argv[1]) 246 if len(sys.argv) >= 4: 247 page = int(sys.argv[2]) 248 if len(sys.argv) == 5: 249 index = int(sys.argv[3]) 250 get_city(city_index, page, index, 1)
原文轉載鏈接:https://xushanxiang.com/2019/10/python-%e8%8e%b7%e5%8f%96-post-%e5%92%8c-get-%e6%95%b0%e6%8d%ae.html