Python으로 Ideone.com에 업로드하는 스크립트를 만들어보자.
-** The post may look strange in immature Japanese. ** ** --I apologize first.
Looking at various programming community sites,
To show your code, to apply other syntax highlighting,
You can see that you are using various Web IDE
s.
This is because it is not possible to write fonts and text colors with HTML tags one by one.
여러 프프로그래밍 커뮤니티를 둘러보다 보면, 자신의 소스 코드를 보여주기 위해, 혹은 Syntax Highlighting을 적용시키기 위해, 여러가지 Web IDE를 사용하는 것을 발견할 수 있다. 일일히 HTML 태그를 적어가며 폰트를 지정하고, 글자 색을 입힐 수는 없는 노릇이다.
codepad, Ideone, JSFiddle (HTML / CSS / Javascript only) Anyway),
Coding Ground (available here on the Web Shell
infrastructure),
There are a lot of things like Pastebin.com (just make it look unexecutable),
For me, ʻideone.com` was the easiest to use.
It supports many languages and can actually execute the code. It's a bonus that the syntax highlighting looks good.
codepad, Ideone, JSFiddle(HTML / CSS / Javascript 밖에 못 쓰지만 아무튼), Coding Ground(여기는 Web Shell 기반으로 이용 가능함), Pastebin.com(실행은 부가능하고, 보여주기만 가능) 등 많이 있는데, 나는
ideone.com
쪽이 제일 쓰기 쉬웠던 것 같다. 지원하는 언어도 많을 뿐더러, 실제로 소스 코드를 실행해 볼 수도 있기 때문이다. Syntax Highlight 기능이 보기 좋게 꾸며주는 것은 덤.
Find a web browser, connect to something like ʻideone.com`, copy my code, and copy the created URL again. Only then can you share the link. It's a really inefficient move. So, let's upload it one after another and get the URL immediately after creating it.
웹 브라우저로 가서, ideone.com 등으로 접속하고, 내 소스 코드를 복붙하여 실행 후, 만들어진 URL을 또 다시 복붙한다. 이제야 링크를 공유할 수 있다. 실로 비효율적인 움직임이다. 그러므로, 작성하고 바로 업로드해서 바로 URL을 얻을 수 있도록 해보자.
For now, let's actually connect to ʻideone.com` and register the code.
우선 실제로 ideone.com 으로 접속해서 소스 코드를 등록해보자.
Simply write only test
.
If you press the Run
button here, a URL that can be shared will appear, but that is not the purpose now.
Seeing that the address changes, it is likely to use the Form
tag and POST
transmission.
It is necessary to find out the address and data of the destination to which the data is transmitted.
Try using the Chrome
developer tools for this.
간단하게
test
만 적어둔다. 여기서 Run 버튼을 누르면 공유가 가능한 URL이 나올테지만, 지금 목적은 그게 아니다. 주소가 바뀐다는 사실을 보면 Form 태그로 POST 전송을 이용할 가능성이 높다. 데이터를 전송할 목적지의 주소와 데이터를 알아낼 필요가 있다. 이를 위해 Chrome의 개발자 도구를 사용한다.
When all the pages have been loaded in this way, clear the network tab and wait. And Run
.
After that, stop the work with the ʻESC` button at the right time. When that happens,
위와 같이 페이지 로딩이 완전히 끝난 상태에서 Network 탭을 비워둔다. 그리고 Run. 그 후 타이밍에 맞춰 ESC 버튼을 눌러 동작을 정지시킨다. 그러면,
As shown in the picture, the information of the page transmitted POST
and the page created to move later appear. If you click on that submit
page and look at the header information, it says:
사진처럼 POST 전송한 페이지의 정보와, 앞으로 이동할 만들어진 페이지가 나타난다. 이 submit 페이지를 클릭하여 헤더 정보를 보면 이렇게 적혀있다.
When connecting to / ideone / Index / submit /
, it receives HTTP 302
and redirects with the Location
header.
Let's take a look at the data sent from here.
/ideone/Index/submit/에 접속하면 HTTP 302를 받으며 Location 헤더를 통해 리다이렉션한다. 이쪽에서 보낸 데이터를 보자.
Various variables were transmitted together. And you can see that the file
variable is the code you created earlier.
If you try to connect by directly entering the address of the Location
header,
여러 변수가 함께 전송되었다. 그리고 file 변수에 아까 적은 소스 코드가 적혀있는 것을 확인할 수 있다. Location 헤더의 주소를 직접 입력하여 접속해보면,
Certainly the correct page is created.
제대로 된 페이지가 확실히 만들어져있다.
Let's organize it here.
여기까지 일단 정리해보자.
--Run
will send the data to the/ ideone / Index / submit /
page with POST
.
HTTP 302 Moved Temporarily
and Location
headers.It's simple. Using this information, let's actually write the script code.
매우 심플하다. 이번에는 이 정보를 이용해서 실제로 스크립트 코드를 적어보자.
The test environment uses Python 3.5
in ʻUbuntu. You have already installed the
requests and
lxmllibraries with
pip. However, since I originally used
Windows 10, I started using
Developer Tools of Chrome
from Windows
.
The point is that it can be anywhere.
테스트 환경은 Ubuntu 에서 Python 3.5를 사용한다. 이미 pip로 requests와 lxml 라이브러리를 설치해둔 상태이다. 그러나 원래 Windows 10을 사용하고 있기 때문에 Chrome의 Developer Tool은 Windows에서 사용했다. 말하자면, 어디든 상관 없다는 이야기다.
First, let's embody it as it appears in the screenshot.
우선, 스크린 샷에 나와있는 대로 구현해보자.
ideone-test-1.py
from requests import get, post
from pprint import pprint
url = "http://ideone.com/ideone/Index/submit/"
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" }
data = {
"p1": "69fc2d31721791fd3912a444035b0ba6",
"p2": 9,
"p3": 20,
"p4": 1710,
"clone_link": "/",
"file": "Lorem ipsum dolor sit amet",
"input": '',
"syntax": 1,
"timelimit": 0,
"note": '',
"_lang": 116,
"public": 1,
"run": 1,
"Submit": '',
}
rs = post(url, headers=headers, data=data)
print(rs)
pprint(dict(rs.headers))
The content of the code was changed to Lorem ipsum dolor sit amet
.
I changed the header ʻUser-Agent to that of
Chrome` because I don't know if it will be banned from the server.
Now run.
소스 코드의 내용은 'Lorem ipsum dolor sit amet' 으로 변경했다. 혹시 서버에서 밴당할까 싶어 User-Agent 헤더도 Chrome의 것으로 바꿨다. 이대로 실행.
<Response [200]>
{'Cache-Control': 'no-store, no-cache, must-revalidate, post-check=0, '
'pre-check=0',
'Connection': 'Keep-Alive',
'Content-Encoding': 'gzip',
'Content-Length': '11067',
'Content-Type': 'text/html',
'Date': 'Tue, 02 Aug 2016 05:23:03 GMT',
'Expires': 'Thu, 19 Nov 1981 08:52:00 GMT',
'Keep-Alive': 'timeout=1, max=90',
'Pragma': 'no-cache',
'Server': 'Apache/2.2.22 (Debian)',
'Set-Cookie': 'JIDEONE=d6e51e6c3ec5a653d7e1be24b87cf050; expires=Thu, '
'02-Aug-2018 05:23:04 GMT; path=/',
'Vary': 'Accept-Encoding',
'X-Powered-By': 'PHP/5.4.15-1'}
No. 200 is coming. Oh, I missed the redirect. Add ʻallow_redirects = True` to the argument of the post function and re-execute.
200번이 온다. 아, 리다이렉트한다는 것을 깜빡했다. post 함수의 인자에 allow_redirects=True 를 추가해서 재실행한다.
<Response [302]>
{'Cache-Control': 'no-store, no-cache, must-revalidate, post-check=0, '
'pre-check=0',
'Connection': 'Keep-Alive',
'Content-Encoding': 'gzip',
'Content-Length': '20',
'Content-Type': 'text/html',
'Date': 'Tue, 02 Aug 2016 05:54:25 GMT',
'Expires': 'Thu, 19 Nov 1981 08:52:00 GMT',
'Keep-Alive': 'timeout=1, max=85',
'Location': '/',
'Pragma': 'no-cache',
'Server': 'Apache/2.2.22 (Debian)',
'Set-Cookie': 'PHPSESSID=2gg67ij2vmh97d3aapqia8sgt4; path=/',
'Vary': 'Accept-Encoding',
'X-Powered-By': 'PHP/5.4.15-1'}
It's finally 302, but the Location
header is wrong.
Well, it's not unexpected. Probably a cookie or p1
hash issue.
This time, let's imitate the behavior of the web browser as it is.
드디어 302가 되었지만, Location 헤더가 맞지 않다. 뭐, 예상 못한 것은 아니다. 아마도 Cookie나 p1 의 해쉬코드가 문제일 것이다. 이번에는 웹 브라우저의 동작을 그대로 따라해보자.
Before writing the code, there are a few things to check. Variables that are non-zero, such as syntax
, public
, and run
, can be guessed with Boolean
variables, but I don't understand the meaning of p1, p2, p3, p4
.
Let's connect to view-source: http://ideone.com/
and check it out.
소스 코드를 적기 전에 몇 가지 확인해야 할 것이 있다. syntax나 public, run 같이 0 혹은 1로 되어있는 변수들은 Boolean 변수로 추측이 가능하지만, p1, p2, p3, p4 의 의미를 알 수가 없다. 당장 view-source:http://ideone.com/ 에 접속해 조사해보자.
You can see it as soon as you scroll down a little. The hashes are directly in the p1
of the ʻinput tags, and the numbers are also entered in the
p2and
p3. By the way ... Is there anything in
p4? ?? ?? You don't have to panic. You should definitely give it somewhere. In such cases, it is often
Javascript. Let's search using
<script or
.js` as a keyword.
스크롤을 조금 내리니 보인다. input 태그 중 p1 에 해쉬코드가 그대로 들어가있고, p2와 p3에는 숫자가 입력되어있다. 그런데... p4에는 아무것도 없어??? 당황할 필요 없다. 분명히 어딘가에서 값을 줄 것이다. 이런 경우에는 대체로 Javascript로 되어 있는 경우가 많다. '<script' 나 '.js' 로 검색해보자.
I looked around a lot, but when I was most interested in that ʻideone-common.js`, I opened it.
여기저기 둘러봤는데, 이 'ideone-common.js'가 가장 의심스러워 열어봤더니,
I found it.
찾았다.
It's a little easier to see because it's made up of jQuery
. It seems that the function protection
is used for p4
to factor p1, p2, p3
and substitute the result.
However, there seems to be a problem. I can't see the definition of the protection
function. And you can see protection
in the ʻevalpart that you dragged. According to the factors of
p, a, c, k, e, d`, it seems to be random reading.
jQuery로 되어 있어 조금 보기 쉽다. p4에 protection이라는 함수로 p1, p2, p3를 인자로 넣어 그 결과를 대입하는 것으로 보인다. 그러나 문제가 있어 보인다. protection 함수의 정의가 보이지 않는다. 그리고 위의 드래그한 eval 부분에 protection이 보인다. p,a,c,k,e,d 라는 인자를 보아하니 난독화된 것 같다.
When you actually run it with a developer tool, a protection
function is created.
It's a little interesting, but it's not the purpose now. Let's analyze the protection
function.
실제로 개발자 도구에서 실행시켜보니 protection 함수가 만들어진다. 살짝 흥미가 동하지만 지금 목적은 이게 아니다. protection 함수를 분석해보자.
protection.js
function protection($a, $b, $c) {
var $r = 0;
$a = mul($c, 2);
for (var $i = 0; $i < $c; $i++) {
$r = add($r, _mul($i, $b))
}
return $r;
}
The code written in one line is hard to see, so I sent it from Online JavaScript Beautifier.
It wasn't a difficult calculation. I don't need $ a
at all.
In short,
한 줄로 써 있는 소스 코드는 보기 힘들기 때문에 Online JavaScript Beautifier에서 개행했다. 어려운 계산은 아니었다. 심지어 $a는 쓰이지도 않는다. 요약해보면,
protection-summary.js
function protection(a, b, c) {
var r = 0;
for (var i = 0; i < c; ++i) r += i * b;
return r;
}
It will be like this. If you organize the calculation formula itself,
이렇게 된다. 계산식 자체를 정리해보면,
protection-summary2.js
function protection(a, b, c) {
return b * ((c - 1) * c) / 2;
}
It will also be like this. This is what I need now. I have all the ingredients. Let's write a Python script.
이렇게도 된다. 지금 필요한 것이 이것. 재료가 모였다. Python 스크립트를 쓰자.
ideone-test-2.py
from requests import get, post
from lxml.etree import HTML
namespaces = dict(re="http://exslt.org/regular-expressions")
from pprint import pprint
''' #1:Get cookies.'''
#Receive the index page first and save cookies and so on.
# (먼저 index 페이지를 받아 Cookie 등을 저장)
url = "http://ideone.com/"
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" }
rs = get(url, headers=headers)
cookies = rs.cookies
root = HTML(rs.content if rs.ok else "<error/>")
data = {
"file": "Lorem ipsum dolor sit amet",
"input": '',
"syntax": 1,
"timelimit": 0,
"note": '',
"public": 1,
"run": 1,
"Submit": '',
}
''' #2: p1, p2,Calculate p4 from p3.(p1, p2, p3을 이용해 p4 계산) '''
#Analyze HTML content and p1 with XPath, p2,Get p3.
# (HTML의 내용을 분석하여 XPath를 이용해 p1, p2, p3을 가져온다.)
#for x in root.xpath('//*[@id="p1" or @id="p2" or @id="p3" or @id="p4"]'):
#You can also do this with a regular expression.
# (정규식으로 이렇게도 가능)
for x in root.xpath('//*[re:test(@id,"p[1-3]")]', namespaces=namespaces):
data[x.get("id")] = x.get("value")
p2 = int(data["p2"])
p3 = int(data["p3"])
p4 = p2 * sum(range(p3))
data["p4"] = str(p4)
''' #3: _Get the lang code list.(_lang 코드 리스트를 획득) '''
#Get the list of language codes directly and use them.
# (언어 코드 리스트를 직접 획득하여 사용해 보자.)
_langs = {}
#for x in root.xpath('//li/*[starts-with(@id,"menu-lang-")]'):
for x in root.xpath('//li/*[re:test(@id,"menu-lang-[0-9]+")]', namespaces=namespaces):
_langs[x.text] = int(x.get("data-id"))
data["_lang"] = _langs["Python 3"]
url = "http://ideone.com/ideone/Index/submit/"
rs = post(url, headers=headers, cookies=cookies, data=data, allow_redirects=False)
print(rs)
pprint(dict(rs.headers))
-# 1: Saved Cookie
to maintain Session
.
protection
function and calculated p4
._lang
code 116
, which corresponds to the Python 3
, I received the entire list of language codes and selected from them.What is the result of the execution?
실행한 결과는?
<Response [302]>
{'Cache-Control': 'no-store, no-cache, must-revalidate, post-check=0, '
'pre-check=0',
'Connection': 'Keep-Alive',
'Content-Encoding': 'gzip',
'Content-Length': '20',
'Content-Type': 'text/html',
'Date': 'Fri, 05 Aug 2016 06:40:25 GMT',
'Expires': 'Thu, 19 Nov 1981 08:52:00 GMT',
'Keep-Alive': 'timeout=1, max=79',
'Location': '/UH3fgT',
'Pragma': 'no-cache',
'Server': 'Apache/2.2.22 (Debian)',
'Set-Cookie': 'settings=%7B%22run_lang%22%3A%22116%22%7D; expires=Wed, '
'01-Feb-2017 06:40:25 GMT; path=/, '
'settings=%7B%22run_lang%22%3A%22116%22%2C%22run_public%22%3A%221%22%7D; '
'expires=Wed, 01-Feb-2017 06:40:25 GMT; path=/, '
'settings=%7B%22run_lang%22%3A%22116%22%2C%22run_public%22%3A%221%22%2C%22run_run%22%3A%221%22%7D; '
'expires=Wed, 01-Feb-2017 06:40:25 GMT; path=/, '
'settings=%7B%22run_lang%22%3A%22116%22%2C%22run_public%22%3A%221%22%2C%22run_run%22%3A%221%22%2C%22run_syntax%22%3A%221%22%7D; '
'expires=Wed, 01-Feb-2017 06:40:25 GMT; path=/, '
'settings=%7B%22run_lang%22%3A%22116%22%2C%22run_public%22%3A%221%22%2C%22run_run%22%3A%221%22%2C%22run_syntax%22%3A%221%22%2C%22run_timelimit%22%3A%220%22%7D; '
'expires=Wed, 01-Feb-2017 06:40:25 GMT; path=/',
'Vary': 'Accept-Encoding',
'X-Powered-By': 'PHP/5.4.15-1'}
The address is often included in the Location
header.
Location 헤더에 주소가 잘 들어가있다.
The page also appears normally.
Well, it can be used as it is, and it can be said that it is almost completed, but let's organize it so that it can be used with bash
.
페이지도 정상적으로 나온다. 뭐, 이대로도 쓸 수 있고, 거의 완성이라고도 할 수 있지만, bash에서 쓸 수 있도록 정리해보자.
ideone.py
from os.path import exists, split, splitext
from sys import argv
from urllib.parse import urlunparse
from requests import get, post
from lxml.etree import HTML
namespaces = dict(re="http://exslt.org/regular-expressions")
from pprint import pprint
extensions = {
".c": "C",
".cpp": "C++14",
".java": "Java7",
".pl": "Perl",
".php": "PHP",
".py": "Python 3",
".ruby": "Ruby",
".sql": "SQL",
".vb": "VB.NET",
".go": "GO",
".js": "JavaScript (rhino)",
".lua": "Lua",
}
def get_ideone(_lang):
url = "http://ideone.com/"
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" }
rs = get(url, headers=headers)
root = HTML(rs.content if rs.ok else "<error/>")
data = {}
for x in root.xpath('//*[re:test(@id,"p[1-3]")]', namespaces=namespaces):
data[x.get("id")] = x.get("value")
p2 = int(data["p2"])
p3 = int(data["p3"])
p4 = p2 * sum(range(p3))
data["p4"] = str(p4)
_langs = {}
for x in root.xpath('//li/*[re:test(@id,"menu-lang-[0-9]+")]', namespaces=namespaces):
_langs[x.text.upper()] = int(x.get("data-id"))
data["_lang"] = _langs[_lang]
return rs.cookies, data
def ideone(path, _lang=''):
d, f = split(path)
n, e = splitext(f)
if len(_lang) <= 0:
_lang = "Text"
if e.lower() in extensions.keys():
_lang = extensions[e.lower()]
cookies, data = get_ideone(_lang.upper())
data.update({
"input": '',
"syntax": 1,
"timelimit": 0,
"note": '',
"public": 1,
"run": 1,
"Submit": '',
})
with open(path, 'r') as ro:
data["file"] = ro.read()
url = "http://ideone.com/ideone/Index/submit/"
headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36" }
rs = post(url, headers=headers, cookies=cookies, data=data, allow_redirects=False)
scheme = "http"
netloc = "ideone.com"
path = rs.headers["Location"]
params = ''
query = ''
favorite = ''
return _lang, urlunparse((scheme, netloc, path, params, query, favorite))
def usage(name):
print("Usage: ./{} <file1> <file2> ...".format(name))
def main(argc, args):
if argc == 1:
d, f = split(__file__)
usage(f)
else:
for i, x in enumerate(args[1:]):
d, f = split(x)
_lang, url = ideone(x)
print(" - #{} ({}): {} - {}".format(i + 1, f, _lang, url))
if __name__ == "__main__":
main(len(argv), argv)
The method of matching file extensions is a bit disappointing, but if you modify the ʻextensions` part in the code and use it, the extension will be automatically recognized and uploaded.
파일 확장자를 매칭시키는 방법이 조금 아쉽지만, 소스 코드 안의 extensions 부분을 수정해서 사용하면 자동적으로 확장자를 인식하여 업로드 가능하다.
root@q:~# python3 ideone.py ideone.py
- #1 (ideone.py): Python 3 - http://ideone.com/5QJTRR
It is out properly. Let's connect. http://ideone.com/5QJTRR
잘 나온다. 접속해보자.
Alright. The code I wrote is included as it is.
오케이. 내가 쓴 소스 소드가 그대로 들어가 있다.
So far, I've first posted to Qiita
on how to waste time efficiently.
I wrote it, but honestly I don't know when to use it.
I will try using it someday.
여기까지 시간을 효율적으로 낭비하는 방법에 대해 Qiita에 처음으로 기술하였다. 내가 적어놓고도 언제 쓸지 솔직히 모르겠다. 언젠간 쓰겠지.
Recommended Posts