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 (바깥 편집)
