2013-05-13 3 views
20

में वेब प्रॉक्सी कैसे लिखें I python में एक वेब प्रॉक्सी लिखने की कोशिश कर रहा हूं। लक्ष्य यूआरएल जैसे http://proxyurl/http://anothersite.com/ पर जाना है और उसे सामान्य रूप से http://anothersite.com की सामग्री देखें। मुझे अनुरोध पुस्तकालय का दुरुपयोग करके सौभाग्य से दूर मिल गया है, लेकिन यह वास्तव में अनुरोध ढांचे का इच्छित उपयोग नहीं है। मैंने पहले twisted के साथ प्रॉक्सी लिखी है, लेकिन मुझे यकीन नहीं है कि मैं इसे करने का प्रयास कर रहा हूं। यहां बताया गया है जहां मैं अब तक यहां हूं ...पायथन

import os 
import urlparse 

import requests 

import tornado.ioloop 
import tornado.web 
from tornado import template 

ROOT = os.path.dirname(os.path.abspath(__file__)) 
path = lambda *a: os.path.join(ROOT, *a) 

loader = template.Loader(path(ROOT, 'templates')) 


class ProxyHandler(tornado.web.RequestHandler): 
    def get(self, slug): 
     if slug.startswith("http://") or slug.startswith("https://"): 
      if self.get_argument("start", None) == "true": 
       parsed = urlparse.urlparse(slug) 
       self.set_cookie("scheme", value=parsed.scheme) 
       self.set_cookie("netloc", value=parsed.netloc) 
       self.set_cookie("urlpath", value=parsed.path) 
      #external resource 
      else: 
       response = requests.get(slug) 
       headers = response.headers 
       if 'content-type' in headers: 
        self.set_header('Content-type', headers['content-type']) 
       if 'length' in headers: 
        self.set_header('length', headers['length']) 
       for block in response.iter_content(1024): 
        self.write(block) 
       self.finish() 
       return 
     else: 
      #absolute 
      if slug.startswith('/'): 
       slug = "{scheme}://{netloc}{original_slug}".format(
        scheme=self.get_cookie('scheme'), 
        netloc=self.get_cookie('netloc'), 
        original_slug=slug, 
       ) 
      #relative 
      else: 
       slug = "{scheme}://{netloc}{path}{original_slug}".format(
        scheme=self.get_cookie('scheme'), 
        netloc=self.get_cookie('netloc'), 
        path=self.get_cookie('urlpath'), 
        original_slug=slug, 
       ) 
     response = requests.get(slug) 
     #get the headers 
     headers = response.headers 
     #get doctype 
     doctype = None 
     if '<!doctype' in response.content.lower()[:9]: 
      doctype = response.content[:response.content.find('>')+1] 
     if 'content-type' in headers: 
      self.set_header('Content-type', headers['content-type']) 
     if 'length' in headers: 
      self.set_header('length', headers['length']) 
     self.write(response.content) 


application = tornado.web.Application([ 
    (r"/(.+)", ProxyHandler), 
]) 

if __name__ == "__main__": 
    application.listen(8888) 
    tornado.ioloop.IOLoop.instance().start() 

बस एक ध्यान दें, मैं अगर वहाँ क्वेरी स्ट्रिंग में सच शुरू = योजना, netloc, और urlpath संरक्षित करने के लिए एक कुकी सेट। इस तरह, किसी भी रिश्तेदार या पूर्ण लिंक जो प्रॉक्सी को हिट करता है उस कुकी को पूर्ण यूआरएल को हल करने के लिए उपयोग करता है।

इस कोड के साथ, यदि आप http://localhost:8888/http://espn.com/?start=true पर जाते हैं तो आप ईएसपीएन की सामग्री देखेंगे। हालांकि, निम्नलिखित साइट पर यह बिल्कुल काम नहीं करता है: http://www.bottegaveneta.com/us/shop/। मेरा सवाल है, ऐसा करने का सबसे अच्छा तरीका क्या है? क्या वर्तमान तरीका मैं इस मजबूत को लागू कर रहा हूं या इस तरह से ऐसा करने के लिए कुछ भयानक नुकसान हैं? यदि यह सही है, तो कुछ ऐसी साइटें क्यों हैं जिन्हें मैंने बिल्कुल काम नहीं किया है?

किसी भी मदद के लिए धन्यवाद।

+0

बोटेगा वेनेटा आपको सीधे संसाधनों तक पहुंचने नहीं देता है। उदाहरण के लिए, http://www.bottegaveneta.com/us/shop/css/bottegaveneta/form.css पर क्लिक करने का प्रयास करें - मुझे एक HTML 404 पृष्ठ मिलता है। –

+2

मुझे लगता है कि यह HTTP रेफरर के साथ करना है। आप इसे भी सेट करने का प्रयास कर सकते हैं। –

+0

@ कोले ओह, आपका मतलब रेफरर है? (https://en.wikipedia.org/wiki/HTTP_referer#Origin_of_the_term_referer) – rakslice

उत्तर

0

मुझे लगता है कि आपको ब्लॉक के आखिरी समय की आवश्यकता नहीं है। यह मेरे लिए काम करने के लिए लगता है:।

class ProxyHandler(tornado.web.RequestHandler): 
    def get(self, slug): 
     print 'get: ' + str(slug) 

     if slug.startswith("http://") or slug.startswith("https://"): 
      if self.get_argument("start", None) == "true": 
       parsed = urlparse.urlparse(slug) 
       self.set_cookie("scheme", value=parsed.scheme) 
       self.set_cookie("netloc", value=parsed.netloc) 
       self.set_cookie("urlpath", value=parsed.path) 
      #external resource 
      else: 
       response = requests.get(slug) 
       headers = response.headers 
       if 'content-type' in headers: 
        self.set_header('Content-type', headers['content-type']) 
       if 'length' in headers: 
        self.set_header('length', headers['length']) 
       for block in response.iter_content(1024): 
        self.write(block) 
       self.finish() 
       return 
     else: 

      slug = "{scheme}://{netloc}/{original_slug}".format(
       scheme=self.get_cookie('scheme'), 
       netloc=self.get_cookie('netloc'), 
       original_slug=slug, 
      ) 
      print self.get_cookie('scheme') 
      print self.get_cookie('netloc') 
      print self.get_cookie('urlpath') 
      print slug 
     response = requests.get(slug) 
     #get the headers 
     headers = response.headers 
     #get doctype 
     doctype = None 
     if '<!doctype' in response.content.lower()[:9]: 
      doctype = response.content[:response.content.find('>')+1] 
     if 'content-type' in headers: 
      self.set_header('Content-type', headers['content-type']) 
     if 'length' in headers: 
      self.set_header('length', headers['length']) 
     self.write(response.content) 
-3

आप कर सकते हैं उपयोगकर्ता अनुरोधों मॉड्यूल

import requests 

proxies = { 
    "http": "http://10.10.1.10:3128", 
    "https": "http://10.10.1.10:1080", 
} 

requests.get("http://example.org", proxies=proxies) 

request docs

+0

क्यों +1 या अधिक नहीं? – sinceq

+8

क्योंकि वह * प्रॉक्सी * लिखने की कोशिश कर रहा है, * एक – Xavier

0

आप सॉकेट मॉड्यूल मानक पुस्तकालय में उपयोग कर सकते हैं और आप लिनक्स epoll के रूप में प्रयोग कर रहे हैं कुंआ।

आप यहाँ एक सरल async सर्वर उदाहरण कोड देख सकते हैं: https://github.com/aychedee/octopus/blob/master/octopus/server.py

3

आप एक असली प्रॉक्सी बनाना चाहते हैं, तो आप उपयोग कर सकते हैं:

tornado-proxy

या

simple proxy based on Twisted

लेकिन मुझे लगता है कि उन्हें आपके मामले के लिए अनुकूलित करना मुश्किल नहीं होगा।

7

मैंने हाल ही में एक समान वेब-एप्लिकेशन लिखा है। ध्यान दें कि मैंने ऐसा किया है। मैं नहीं कह रहा हूं कि आपको ऐसा करना चाहिए। पूर्ण

के सापेक्ष से

बदलने विशेषता मान और भी बहुत कुछ सिर्फ एक पृष्ठ को लाना और ग्राहक को पेश करने की तुलना में अधिक शामिल है: ये नुकसान मैं भर में आया हैं। कई बार आप बिना किसी त्रुटि के वेबपृष्ठ को प्रॉक्सी करने में सक्षम नहीं हैं।

कुछ ऐसी साइटें क्यों हैं जिन्हें मैंने बिल्कुल काम नहीं किया है?

कई वेबपृष्ठ वेबपृष्ठ को अच्छी तरह से स्वरूपित तरीके से प्रदर्शित करने के लिए संसाधनों के सापेक्ष पथों पर भरोसा करते हैं।उदाहरण के लिए, इस छवि टैग:

<img src="/header.png" /> 

ग्राहक के लिए एक अनुरोध कर रही है में परिणाम होगा:

http://proxyurl/header.png 

कौन सा विफल रहता है।

:

http://anothersite.com/header.png. 

तो, तुम पर सभी टैगBeautifulSoup की तरह कुछ, पाश के साथ HTML दस्तावेज़ को पार्स और जैसे विशेषताओं के लिए जांच करने की आवश्यकता: 'src' मूल्य के लिए परिवर्तित किया जाना चाहिए

'src', 'lowsrc', 'href' 

और परिवर्तन उनके मूल्यों तदनुसार ताकि टैग हो जाता है:

<img src="http://anothersite.com/header.png" /> 

यह विधि केवल छवि की तुलना में अधिक टैग पर लागू होती है। एक, स्क्रिप्ट, लिंक, ली और फ्रेम कुछ तुम भी बदलना चाहिए रहे हैं।

एचटीएमएल shenanigans

पूर्व विधि आप अब तक मिलना चाहिए, लेकिन आप अभी तक नहीं किया है।

दोनों

<style type="text/css" media="all">@import "/stylesheet.css?version=120215094129002";</style> 

और

<div style="position:absolute;right:8px;background-image:url('/Portals/_default/Skins/BE/images/top_img.gif');height:200px;width:427px;background-repeat:no-repeat;background-position:right top;" > 

कोड है कि तक पहुँचने और BeautifulSoup का उपयोग कर संशोधित करने के लिए मुश्किल है के उदाहरण हैं।

पहले उदाहरण में एक रिश्तेदार यूरी के लिए एक सीएसएस @ आयात है। दूसरा एक इनलाइन सीएसएस कथन से 'url()' विधि से संबंधित है।

मेरी स्थिति में, मैंने इन मानों को मैन्युअल रूप से संशोधित करने के लिए भयानक कोड लिखना समाप्त कर दिया। आप इसके लिए रेगेक्स का उपयोग करना चाह सकते हैं लेकिन मुझे यकीन नहीं है।

पुनर्निर्देश

अजगर-अनुरोध या Urllib2 आप आसानी से स्वचालित रूप से पुनर्निर्देश पालन कर सकते हैं के साथ

। बस नया (बेस) यूरी क्या बचा है उसे बचाने के लिए याद रखें; आपको 'गुणों को पूर्ण से संबंधित' ऑपरेशन में बदलने के लिए इसकी आवश्यकता होगी।

आपको 'हार्डकोडेड' रीडायरेक्ट से निपटने की भी आवश्यकता है।इस तरह के रूप में एक:

<meta http-equiv="refresh" content="0;url=http://new-website.com/"> 

की जरूरत के लिए बदला जा रहे हैं:

<meta http-equiv="refresh" content="0;url=http://proxyurl/http://new-website.com/"> 

बेस टैग

base tag एक दस्तावेज़ में सभी सापेक्ष URL के लिए आधार URL/लक्ष्य निर्दिष्ट करता है। आप शायद मूल्य बदलना चाहते हैं।

अंत में किया गया?

नहीं। कुछ वेबसाइटें स्क्रीन पर अपनी सामग्री खींचने के लिए जावास्क्रिप्ट पर भारी निर्भर करती हैं। ये साइट प्रॉक्सी के लिए सबसे कठिन हैं। मैं वेबपृष्ठों को लाने और मूल्यांकन करने और ग्राहक को परिणाम प्रस्तुत करने के लिए PhantomJS या Ghost जैसे कुछ का उपयोग करने के बारे में सोच रहा हूं।

शायद मेरी source code आपकी मदद कर सकता है। आप इसे किसी भी तरह से इस्तेमाल कर सकते हैं।

+3

का उपयोग न करने के लिए आप दस्तावेज़ हेडर में '' टैग चिपका सकते हैं ताकि एक में रिश्तेदार यूआरएल को ठीक किया जा सके। (लेकिन अगर पहले से कोई नहीं है!) – kindall

+0

मैंने इसके बारे में नहीं सोचा था! मैं इसे आज़माउंगा। धन्यवाद! – cpb2

0

जाहिर है, मैं इसका जवाब देने में काफी देर हो चुकी हूं, लेकिन थोड़ी देर पहले इसे ठोकर खाई। मैं आपकी आवश्यकताओं के समान कुछ लिख रहा हूं।

यह एक HTTP पुनरावर्तक का अधिक है, लेकिन इसका पहला कार्य प्रॉक्सी ही है। यह अभी तक पूरी तरह से पूर्ण नहीं है और अभी इसके लिए मुझे कोई पढ़ा नहीं है - लेकिन वे मेरी todo सूची पर हैं।

मैंने इसे प्राप्त करने के लिए mitmproxy का उपयोग किया है। यह वहां कोड का सबसे सुंदर टुकड़ा नहीं हो सकता है और मैंने दोहराने की कार्यक्षमता प्राप्त करने के लिए यहां और वहां कई हैक का उपयोग किया है। मुझे डिफ़ॉल्ट रूप से mitmproxy पता है कि आसानी से दोहराने वाली चीज़ों को आसानी से प्राप्त करने के तरीके हैं, लेकिन मेरे मामले में कुछ निश्चित आवश्यकता थी जहां मैं mitmproxy द्वारा प्रदान की गई उन सुविधाओं का उपयोग नहीं कर सका।

आप https://github.com/c0n71nu3/python_repeater/ पर प्रोजेक्ट पा सकते हैं रेपो अभी भी मेरे द्वारा अपडेट किए जा रहे हैं और जब कोई विकास हो रहा है।

उम्मीद है कि यह आपके लिए कुछ मदद करने में सक्षम होगा।