project:embeddedpythonusingcapi
차이
문서의 선택한 두 판 사이의 차이를 보여줍니다.
project:embeddedpythonusingcapi [2014/03/03 14:45] – [예제: URL의 콘텐츠 가져오기] changwoo | project:embeddedpythonusingcapi [2014/10/09 21:24] (현재) – 바깥 편집 127.0.0.1 | ||
---|---|---|---|
줄 396: | 줄 396: | ||
===== 함수 호출 ===== | ===== 함수 호출 ===== | ||
==== 모듈 함수 ==== | ==== 모듈 함수 ==== | ||
- | 모듈의 함수는 어떤 모듈에서 바로 호출가능하므로 '' | + | 모듈의 함수는 어떤 모듈에서 바로 호출가능하므로 '' |
<code c> | <code c> | ||
/* import scripts.mydef */ | /* import scripts.mydef */ | ||
줄 409: | 줄 409: | ||
} | } | ||
</ | </ | ||
- | 또는 함수의 객체를 끝까지 레퍼런스하여 | + | 또는 함수의 객체를 끝까지 레퍼런스한 다음 '' |
<code c> | <code c> | ||
/* Multiply = my_def.Multiply */ | /* Multiply = my_def.Multiply */ | ||
줄 426: | 줄 426: | ||
==== 클래스 함수 ==== | ==== 클래스 함수 ==== | ||
- | 모듈의 내 함수나 클래스의 함수나 같은 관점에서 바라볼 수 있습니다. | + | 모듈의 내 함수나 클래스의 함수나 같은 관점에서 바라볼 수 있습니다. '' |
<code c> | <code c> | ||
줄 451: | 줄 451: | ||
} | } | ||
</ | </ | ||
+ | |||
+ | 그런데 이렇게 모듈을 끄집어 내고, 클래스를 끄집어 내고, 함수를 끄집어내고... 끄집어내고 끄집어내다 보면 if 문의 홍수가 나죠. 레퍼런스 관리는 철저하게 해야 하는데, 그렇다고 에러 체크를 안 할 수도 없고... 결국 goto 명령을 쓰게 되더라구요. | ||
+ | |||
===== 리턴 값 추출 ===== | ===== 리턴 값 추출 ===== | ||
함수 호출을 통해 PyObject 객체의 레퍼런스를 받았다면, | 함수 호출을 통해 PyObject 객체의 레퍼런스를 받았다면, | ||
줄 457: | 줄 460: | ||
기본 자료형들은 매우 간결하게 '' | 기본 자료형들은 매우 간결하게 '' | ||
+ | ==== 튜플/ | ||
+ | 이외의 자료형들은 레퍼런스를 참고하라는 마법의 단어로 생략하도록 하겠습니다. 여기까지 읽고 이해했다면 아마 레퍼런스를 보고 어떻게 값을 가져올지 감이 잡히셨으리라 생각합니다. 레퍼런스의 ' | ||
+ | |||
+ | 파이썬 확장에 대해서는 그나마 몇몇 문서들을 만나긴 했지만, 파이썬 삽입에 대해서는 그다지 문서가 많지 않더군요. 처음에는 갈팡질팡했습니다. 그렇지만 문서를 작성하는 과정을 통해 C API를 레퍼런스를 보다 정독해보고 나니 그렇게까지 어려운 일은 아니라는 결론을 내렸습니다. 결국 파이썬 객체를 다루는 것이니, 파이썬이 동작하는 방식을 유추해보면 거의 흐름이 그려지게 되더군요. | ||
===== 예제: URL의 콘텐츠 가져오기 ===== | ===== 예제: URL의 콘텐츠 가져오기 ===== | ||
줄 463: | 줄 470: | ||
아래 예제는 인자로 받은 URL로부터 약간의 HTML을 분석하는 코드입니다. 모든 '' | 아래 예제는 인자로 받은 URL로부터 약간의 HTML을 분석하는 코드입니다. 모든 '' | ||
- | 제가 C 프로그램에 아주아주 정통한 건 아닌지라 확실하게 단언할 수는 없지만, 일반적으로 별도의 라이브러리 없이 프로그래머가 소켓을 통해 생짜로 C에서 이렇게 HTTP 서버에 접속해서 HTML을 받아오고, | + | 제가 C 프로그램에 아주아주 정통한 건 아닌지라 확실하게 단언할 수는 없지만, 일반적으로 별도의 라이브러리 없이 프로그래머가 소켓을 통해 생짜로 C에서 이렇게 HTTP 서버에 접속해서 HTML을 받아오고, |
C와 파이썬 사이에는 다음과 같은 입출력을 주고받기로 맞추었습니다. | C와 파이썬 사이에는 다음과 같은 입출력을 주고받기로 맞추었습니다. | ||
줄 470: | 줄 477: | ||
* 이미지 저장은 모두 파이썬 측에서 처리합니다. | * 이미지 저장은 모두 파이썬 측에서 처리합니다. | ||
- | ==== 정규표현식 테스트 ==== | + | ==== finder 파이썬 모듈 ==== |
+ | <code python finder.py> | ||
+ | # -*- coding: utf-8 -*- | ||
+ | |||
+ | import urllib | ||
+ | import urlparse | ||
+ | import os | ||
+ | import re | ||
+ | import sys | ||
+ | |||
+ | class url_finder: | ||
+ | |||
+ | def __init__(self, | ||
+ | html = self.get_html(sys.argv[1]) | ||
+ | |||
+ | # url trimming | ||
+ | url_parsed = urlparse.urlparse(url) | ||
+ | self.url = ' | ||
+ | |||
+ | # exclude file name | ||
+ | spl = url_parsed[2].split('/' | ||
+ | if len(spl) > 1: | ||
+ | self.url += '/' | ||
+ | |||
+ | # links, and images | ||
+ | self.links = self.get_all_external_links(html) | ||
+ | self.save_all_images(html) | ||
+ | |||
+ | def get_all_external_links(self, | ||
+ | found = re.findall(r'< | ||
+ | return found | ||
+ | |||
+ | def save_all_images(self, | ||
+ | if os.path.exists(' | ||
+ | os.mkdir(' | ||
+ | |||
+ | for s in self.get_all_image_links(html): | ||
+ | url = self.trim_image_url(s) | ||
+ | filename = ' | ||
+ | content = self.get_html(url) | ||
+ | with open(filename, | ||
+ | print " | ||
+ | f.write(content) | ||
+ | |||
+ | def get_all_image_links(self, | ||
+ | found = re.findall(r'< | ||
+ | return set(x[0] for x in found) | ||
+ | |||
+ | def trim_image_url(self, | ||
+ | if src_url[:4] == ' | ||
+ | return src_url | ||
+ | elif src_url[0] == '/': | ||
+ | return " | ||
+ | else: | ||
+ | return " | ||
+ | |||
+ | def get_html(self, | ||
+ | u = urllib.urlopen(url) | ||
+ | html = u.read() | ||
+ | u.close() | ||
+ | return html | ||
+ | |||
+ | if __name__ == " | ||
+ | finder = url_finder(" | ||
+ | for x in finder.links: | ||
+ | print x | ||
+ | </ | ||
+ | |||
+ | ==== finder C 코드 ==== | ||
+ | 에러 처리가 불완전하지만 보여주는 것에 초점을 맞춰 | ||
+ | <code c finder.c> | ||
+ | #include < | ||
+ | |||
+ | int main(int argc, char** argv) | ||
+ | { | ||
+ | Py_SetProgramName(argv[0]); | ||
+ | Py_Initialize(); | ||
+ | |||
+ | if (Py_IsInitialized()) { | ||
+ | /* module, class, instance */ | ||
+ | PyObject *mod = NULL, *cls = NULL, *ins = NULL; | ||
+ | |||
+ | /* argument, return */ | ||
+ | PyObject *url = NULL, *ret = NULL; | ||
+ | |||
+ | PySys_SetArgv(argc, | ||
+ | |||
+ | mod = PyImport_ImportModule(" | ||
+ | cls = PyObject_GetAttrString(mod, | ||
+ | |||
+ | /* argument must be a tuple */ | ||
+ | url = PyTuple_New(1); | ||
+ | PyTuple_SetItem(url, | ||
+ | |||
+ | ins = PyObject_CallObject(cls, | ||
+ | ret = PyObject_GetAttrString(ins, | ||
+ | |||
+ | if (PyList_Check(ret)) { | ||
+ | PyObject* iter = PyObject_GetIter(ret); | ||
+ | PyObject* item; | ||
+ | |||
+ | while(item = PyIter_Next(iter)) { | ||
+ | if (PyString_Check(item)) { | ||
+ | printf(" | ||
+ | } | ||
+ | Py_XDECREF(item); | ||
+ | } | ||
+ | Py_XDECREF(iter); | ||
+ | } | ||
+ | Py_XDECREF(ret); | ||
+ | Py_XDECREF(ins); | ||
+ | Py_XDECREF(url); | ||
+ | Py_XDECREF(cls); | ||
+ | Py_XDECREF(mod); | ||
+ | Py_Finalize(); | ||
+ | } | ||
+ | |||
+ | return 0; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | 파이썬 | ||
+ | |||
+ | ===== 마치며 ===== | ||
+ | 파이썬에는 여러 라이브러리들이 잘 갖춰져 있고, 또 쓰기 매우 쉽게 되어 있습니다. 기존의 어떤 작업을 C/C++, 혹은 다른 언어 기반으로 하고 있다가 전혀 다른 아이디어를 떠올리게 되었습니다. 사용 중인 언어 환경에서는 외부라이브러리를 가져다가 빌드도 하고 세팅도 해야하고 ... 이것저것 밑작업도 많이 해야 하고 본 코드를 작성하는데도 조금 시간이 걸릴 수 있습니다. | ||
+ | |||
+ | 이럴 때 이 새로운 부분만을 파이썬 스크립트로 프로토타이핑을 할 수 있습니다. 그런데 양 프로그램간 데이터 전송, 좀 더 거창하게는 프로세스 통신이 이뤄지면 보다 더 좋겠죠. 이럴 때 파이썬 삽입이 적합한 것 같습니다. | ||
+ | |||
+ | 저도 이 문서를 제작하게 된 계기가 된 것이, 어떤 프로그램을 제작하는데, | ||
project/embeddedpythonusingcapi.1393857916.txt.gz · 마지막으로 수정됨: 2014/10/09 21:23 (바깥 편집)