일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- string
- Tkinter
- SQL
- PySpark
- Python
- c#
- Google Spreadsheet
- math
- 파이썬
- Java
- GIT
- hive
- Mac
- gas
- Kotlin
- PANDAS
- Redshift
- django
- Github
- Excel
- list
- Google Excel
- PostgreSQL
- dataframe
- numpy
- Apache
- google apps script
- matplotlib
- array
- Today
- Total
달나라 노트
Python io : BytesIO (메모리에 엑셀 파일 저장하기, BytesIO로 xlsx 파일 객체 생성하기) 본문
Python io : BytesIO (메모리에 엑셀 파일 저장하기, BytesIO로 xlsx 파일 객체 생성하기)
CosmosProject 2023. 10. 27. 19:55
DataFrame을 xlsx 파일로 생성하려면 to_excel() method를 사용합니다.
import pandas as pd
df_test = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
print(df_test)
dir = 'output/df_test.xlsx'
df_test.to_excel(dir, index=False, sheet_name='test')
이런 식이죠.
이렇게 하면 제가 지정한 'output/df_test.xlsx'라는 경로에 파일이 생성됩니다.
import pandas as pd
df_test_1 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
df_test_2 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'price': [1000, 800, 3000, 2030, 6000]
})
dir = 'output/df_test.xlsx'
xlsx_writer = pd.ExcelWriter(dir, engine='openpyxl')
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1')
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2')
xlsx_writer.close()
xlsx 파일은 하나의 파일 안에 여러 sheet가 존재할 수 있으므로 위처럼 ExcelWriter를 이용하여 여러 탭을 가진 xlsx file을 생성할 수도 있습니다.
Local 환경에서는 위 방법을 문제없이 사용할 수 있습니다.
근데 만약 서버상에서 여러 개의 DataFrame을 하나의 xlsx파일로 합쳐서 메일을 보내거나 어딘가로 전송하는 등의 작업을 해야한다면 어떻게 해야할까요?
물론 서버 상에서도 코드를 upload해두고 to_excel() method를 사용하여 서버 상의 어떤 경로에 xlsx 파일을 생성해두고 그 파일을 참조하여 이 문제를 해결할 수 있습니다.
다만 이 문제는 서버의 설정에 따라 사용이 불가능할 수 있는데 대표적으로
- 서버에서 to_excel() method 사용을 금지해놓은 경우
- to_excel() method 포함 어떤 파일을 생성하는 것 자체를 금지해놓은 경우
- 파일 생성은 가능하나 주기적으로 파일 삭제를 하는 경우
등이 있습니다.
이런 설정의 서버라면 to_excel()을 아예 사용할 수 없거나 사용한다고해도 생성한 파일이 서버에 의해 사라져서 다음 라인의 코드를 실행할 때 에러가 발생할 수 있죠.
이럴 때 BytesIO를 사용할 수 있습니다.
그 원리를 간단하게 말하자면 xlsx 객체를 Bytes IO 메모리에 저장해두고 사용하는 방식입니다.
I/O는 Input / Output의 약자로 입출력이라는 의미를 가집니다.
대충 해석해보면 BytesIO는 Bytes를 Input / Output할 수 있게 해주는 무언가라고 짐작할 수 있겠네요.
StringIO는 메모리에서 String data를 다루고,
BytesIO는 메모리에서 Binary data를 다룰 수 있게 해줍니다.
StringIO, BytesIO는 실제 파일같은 객체를 생성하고 다룰 수 있게 해줍니다.
그래서 파일같은 정보를 다룰 때 유용합니다.
사용 방법을 봅시다.
import pandas as pd
from io import BytesIO
df_test_1 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
df_test_2 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'price': [1000, 800, 3000, 2030, 6000]
})
bio = BytesIO() # ByesIO 객체 생성
xlsx_writer = pd.ExcelWriter(bio, engine='openpyxl') # ExcelWirter를 BytesIO 객체를 대상으로 생성
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1') # xlsx에 원하는 sheet 생성
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2') # xlsx에 원하는 sheet 생성
xlsx_writer.save() # BytesIO 메모리에 xlsx 정보 저장
bio.seek(0)
사용법 자체는 ExcelWriter를 이용하는 기존의 방식과 크게 다르지 않습니다.
다만 BytesIO() 객체를 생성한 후 ExcelWriter를 BytesIO() 객체를 대상으로 생성한다는 특징이 있죠.
그리고 마지막에 save를 해주면 BytesIO 메모리에 xlsx 파일의 정보가 저장됩니다.
import pandas as pd
from io import BytesIO
df_test_1 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
df_test_2 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'price': [1000, 800, 3000, 2030, 6000]
})
bio = BytesIO() # ByesIO 객체 생성
xlsx_writer = pd.ExcelWriter(bio, engine='openpyxl') # ExcelWirter를 BytesIO 객체를 대상으로 생성
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1') # xlsx에 원하는 sheet 생성
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2') # xlsx에 원하는 sheet 생성
xlsx_writer.save() # BytesIO 메모리에 xlsx 정보 저장
bio.seek(0)
xlsx_file = bio.read() # 방금 저장했던 BytesIO() 객체에 담긴 내용을 읽어오기
ByesIO 메모리에 저장된 내용을 읽어오고 싶으면 위처럼 BytesIO() 객체의 read() method를 사용하면 됩니다.
그러면 bio 객체에 저장된 xlsx 파일 객체를 불러올 수 있으며 이를 다양하게 사용할 수 있습니다.
그리고 위 코드에서 seek(0) 이라는 method가 보이는데 BytesIO()로 file을 save() 하여 작성한 후 다시 파일을 읽어오기 위해서는 seek(0) method를 사용해야 합니다.
그렇지 않으면 나중에 BytesIO로부터 file을 읽어올 때 비어있는 Bytes data가 얻어질것입니다. (이것은 StringIO에서도 마찬가지 입니다.)
참고 2 = https://www.geeksforgeeks.org/stringio-module-in-python/
seek() method는 내가 작성한 file의 cursor position을 설정하는데 사용됩니다.
보통 file을 읽어오거나 쓸 때에는 cursor가 가장 최근 index로 설정됩니다.
그래서 seek(0) method를 통해 다시 cursor를 처음으로 돌려놔야 내가 작성한 파일을 이후에 제대로 읽어올 수 있습니다.
위에 첨부한 참고 2 링크에 아주 좋은 예시가 있습니다.
import pandas as pd
from io import BytesIO
df_test_1 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
df_test_2 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'price': [1000, 800, 3000, 2030, 6000]
})
bio = BytesIO() # ByesIO 객체 생성
xlsx_writer = pd.ExcelWriter(bio, engine='openpyxl') # ExcelWirter를 BytesIO 객체를 대상으로 생성
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1') # xlsx에 원하는 sheet 생성
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2') # xlsx에 원하는 sheet 생성
xlsx_writer.save() # BytesIO 메모리에 xlsx 정보 저장
# bio.seek(0)
xlsx_file = bio.read() # 방금 저장했던 BytesIO() 객체에 담긴 내용을 읽어오기
print(xlsx_file)
-- Result
b''
직접 seek(0) method를 사용하지 않는 예시를 만들어봤습니다.
bio.read()를 통해 bio 객체에 저장된 xlsx file 정보를 읽어와서 print해보았지만 그 결과는 비어있는 binary data입니다.
import pandas as pd
from io import BytesIO
df_test_1 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
df_test_2 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'price': [1000, 800, 3000, 2030, 6000]
})
bio = BytesIO() # ByesIO 객체 생성
xlsx_writer = pd.ExcelWriter(bio, engine='openpyxl') # ExcelWirter를 BytesIO 객체를 대상으로 생성
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1') # xlsx에 원하는 sheet 생성
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2') # xlsx에 원하는 sheet 생성
xlsx_writer.save() # BytesIO 메모리에 xlsx 정보 저장
bio.seek(0)
xlsx_file = bio.read() # 방금 저장했던 BytesIO() 객체에 담긴 내용을 읽어오기
print(xlsx_file)
-- Result
b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[WFZ\xc1\x0c\x82\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00docProps/app.xmlM\x8eM\x0b\xc20\x10D\xffJ\xe9\xddnU\xf0 1 \xd4\xa3\xe0\xc9{H76\x90dCv\x85\xfc|S\xc1\x8f\xdb<\xde0\x8c\xba\x15\xcaX\xc4#w5\x86\xc4\xa7~\x11\xc9G\x00\xb6\x0bF\xc3C\xd3\xa9\x19G%\x1aiX\x1e@\xcey\x8b\x13\xd9g\xc4$\xb0\x1b\xc7\x03`\x15L3\xce\x9b\xfc\x1d\xec\xb5:\xe7\x1c\xbc5\xe2)\xe9\xab\xb7\x85\x98\x9ct\x97j1(\xf8\x97k\xf3\x8e\x85\xd7\xbc\x1f\xb6o\xf9a\x05\xbf\x93\xfa\x05PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xdb\xca)$\xeb\x00\x00\x00\xcb\x01\x00\x00\x11\x00\x00\x00docProps/core.xml\xa5\x91\xc1N\xc30\x0c\x86_e\xea\xbdu\xd3j\x03E].\xa0\x9d\x86\x84\xc4$\x10\xb7\xc8\xf1\xb6hM\x1b%F\xed\xde\x9e\xb6l\x1d\x08n\x1c\xe3\xff\xf3g[\xa9\xd0Kl\x03=\x87\xd6S`Kq\xd1\xbb\xba\x89\x12\xfd:92{\t\x10\xf1HN\xc7l \x9a!\xdc\xb7\xc1i\x1e\x9e\xe1\x00^\xe3I\x1f\x08\x8a<_\x81#\xd6F\xb3\x86Q\x98\xfa\xd9\x98\\\x94\x06g\xa5\xff\x08\xf5$0\x08T\x93\xa3\x86#\x88L\xc0\x8de\n.\xfe\xd90%3\xd9G;S]\xd7e]9q\xc3F\x02\xde\x9e\xb6/\xd3\xf2\xa9m"\xeb\x06)Q\x95A\x89\x814\xb7A\x8d\x17\xf9s_W\xf0\xadX]f\x7f\x15\xc8,\x86\t\x92\xcf\x9e\xd6\xc95y-\x1f\x1ew\x9bD\x15yQ\xa6"O\x8b\xbb\x9d\x10r\xb9\x92\xcb\xfb\xf7\xd1\xf5\xa3\xff&t\xad\xb1{\xfb\x0f\xe3U\xa0*\xf8\xf5o\xea\x13PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\x99\\\x9c#\x10\x06\x00\x00\x9c\'\x00\x00\x13\x00\x00\x00xl/theme/theme1.xml\xedZ[s\xda8\x14~\xef\xaf\xd0xg\xf6m\x0b\xc66\x81\xb6\xb4\x13siv\xdb\xb4\x99\x84\xedN\x1f\x85\x11X\x8dlyd\x91\x84\x7f\xbfG6\x10\xcb\x96\r\xed\x92M\xba\x9b<\x04,\xe9\xfb\xceEG\xe7\xe88y\xf3\xee.b\xe8\x86\x88\x94\xf2x`\xd9/\xdb\xd6\xbb\xb7/\xde\xe0W2$\x11A0\x19\xa7\xaf\xf0\xc0\n\xa5L^\xb5Zi\x00\xc38}\xc9\x13\x12\xc3\xdc\x82\x8b\x08Kx\x14\xcb\xd6\\\xe0[\x1a/#\xd6\xea\xb4\xdb\xddV\x84il\xa1\x18Gd`}^,h@\xd0TQZo_ \xb4\xe5\x1f3\xf8\x15\xcbT\x8de\xa3\x01\x13WA&\xb9\x88\xb4\xf2\xf9l\xc5\xfc\xda\xde>e\xcf\xe9:\x1d2\x81n0\x1bX \x7f\xceo\xa7\xe4NZ\x88\xe1T\xc2\xc4\xc0jg?Vk\xc7\xd1\xd2H\x80\x82\xc9}\x94\x05\xbaI\xf6\xa3\xd3\x15\x082\r;:\x9dX\xcev|\xf6\xc4\xed\x9f\x8c\xca\xdat4m\x1a\xe0\xe3\xf1x8\xb6\xcb\xd2\x8bp\x1c\x04\xe0Q\xbb\x9e\xc2\x9d\xf4l\xbf\xa4A\t\xb4\xa3i\xd0d\xd8\xf6\xda\xae\x91\xa6\xaa\x8dSO\xd3\xf7}\xdf\xeb\x9bh\x9c\n\x8d[O\xd3kw\xdd\xd3\x8e\x89\xc6\xad\xd0x\r\xbe\xf1O\x87\xc3\xae\x89\xc6\xab\xd0t\xebi&\'\xfd\xaek\xa4\xe9\x16hBF\xe3\xebz\x12\x15\xb5\xe5@\xd3 \x00Xpv\xd6\xcc\xd2\x03\x96^)\xfau\x94\x1a\xd9\x1d\xbb\xddA\\\xf0X\xee9\x89\x11\xfe\xc6\xc5\x04\xd6i\xd2\x19\x964Fr\x9d\x90\x05\x0e\x007\xc4\xd1LP|\xafA\xb6\x8a\xe0\xc2\x92\xd2\\\x90\xd6\xcf)\xb5P\x1a\x08\x9a\xc8\x81\xf5G\x82!\xc5\xdc\xaf\xfd\xf5\x97\xbb\xc9\xa43z\x9d}:\xcek\x94\x7fi\xab\x01\xa7\xed\xbb\x9b\xcf\x93\xfcs\xe8\xe4\x9f\xa7\x93\xd7MB\xcep\xbc,\t\xf1\xfb#[a\x87\'n;\x13r:\x1cgB|\xcf\xf6\xf6\x91\xa5%2\xcf\xef\xf9\n\xebN<g\x1fV\x96\xb0]\xcf\xcf\xe4\x9e\x8cr#\xbb\xdd\xf6X}\xf6OGn#\xd7\xa9\xc0\xb3"\xd7\x94F$E\x9f\xc8-\xba\xe4\x118\xb5I\r2\x13?\x08\x9d\x86\x98jP\x1c\x02\xa4\t1\x96\xa1\x86\xf8\xb4\xc6\xac\x11\xe0\x13}\xb7\xbe\x08\xc8\xdf\x8d\x88\xf7\xabo\x9a=W\xa1XI\xda\x84\xf8\x10F\x1a\xe2\x9cs\xe6s\xd1l\xfb\x07\xa5F\xd1\xf6U\xbc\xdc\xa3\x97X\x15\x01\x97\x18\xdf4\xaa5,\xc5\xd6x\x95\xc0\xf1\xad\x9c<\x1d\x13\x12\xcd\x94\x0b\x06A\x86\x97$&\x12\xa99~MH\x13\xfe+\xa5\xda\xfe\x9c\xd3@\xf0\x94/$\xfaJ\x91\x8fi\xb3#\xa7t&\xcd\xe83\x1a\xc1F\xaf\x1bu\x87h\xd2<z\xfe\x05\xf9\x9c5\n\x1c\x91\x1b\x1d\x02g\x1b\xb3F!\x84i\xbb\xf0\x1e\xaf$\x8e\x9a\xad\xc2\x11+B>b\x196\x1ar\xb5\x16\x81\xb6q\xa9\x84`Z\x12\xc6\xd1xN\xd2\xb4\x11\xfcY\xac5\x93>`\xc8\xec\xcd\x91u\xce\xd6\x91\x0e\x11\x92^7B>b\xce\x8b\x90\x11\xbf\x1e\x868J\x9a\xed\xa2qX\x04\xfd\x9e^\xc3I\xc1\xe8\x82\xcbf\xfd\xb8~\x86\xd53l,\x8e\xf7G\xd4\x17J\xe4\x0f&\xa7?\xe924\x07\xa3\x9aY\t\xbd\x84Vj\x9f\xaa\x874>\xa8\x1e2\n\x05\xf1\xb9\x1e>\xe5zx\n7\x96\xc6\xbcP\xae\x82{\x01\xff\xd1\xda7\xc2\xab\xf8\x82\xc09\x7f.}\xcf\xa5\xef\xb9\xf4=\xa1\xd2\xb77#}g\xc1\xd3\x8b[\xdeFn[\xc4\xfb\xae1\xda\xd74.(cWr\xcd\xc8\xc7T\xaf\x93)\xd89\x9f\xc0\xec\xfdh>\x9e\xf1\xed\xfa\xd9$\x84\xaf\x9aY-#\x16\x90K\x81\xb3A$\xb8\xfc\x8b\xca\xf0*\xc4\t\xe8d[%\t\xcbT\xd3e7\x8a\x12\x9eB\x1bn\xe9S\xf5J\x95\xd7\xe5\xaf\xb9(\xb8<[\xe4\xe9\xaf\xa1t>,\xcf\xf9<_\xe7\xb4\xcd\x0b3C\xb7rK\xea\xb6\x94\xbe\xb5&8J\xf4\xb1\xccpN\x1e\xcb\x0c;g<\x92\x1d\xb6w\xa0\x1d5\xfb\xf6]v\xe4#\xa50S\x97C\xb8\x1aB\xbe\x03m\xba\x9d\xdc:8\x9e\x98\x91\xb9\n\xd3R\x90o\xc3\xf9\xe9\xc5x\x1a\xe29\xd9\x04\xb9}\x98Wm\xe7\xd8\xd1\xd1\xfb\xe7\xc1Q\xb0\xa3\xef<\x96\x1d\xc7\x88\xf2\xa2!\xee\xa1\x86\x98\xcf\xc3C\x87y{_\x98g\x95\xc6P4\x14ml\xac$,F\xb7`\xb8\xd7\xf1,\x14\xe0d`-\xa0\x07\x83\xafQ\x02\xf2RU`1[\xc6\x03+\x90\xa2|L\x8cE\xe8p\xe7\x97\\_\xe3\xd1\x92\xe3\xdb\xa6e\xb5n\xaf)w\x19m"R9\xc2i\x98\x13g\xab\xca\xdee\xb1\xc1U\x1d\xcfU[\xf2\xb0\xbej=\xb4\x15N\xcf\xfeY\xad\xc8\x9f\x0c\x11N\x16\x0b\x12Hc\x94\x17\xa6J\xa2\xf3\x19S\xbe\xe7+I\xc4U8\xbfE3\xb6\x12\x97\x18\xbc\xe3\xe6\xc7qNS\xb8\x12v\xb6\x0f\x022\xb9\xbb9\xa9ze1g\xa6\xf2\xdf-\x0c\t,[\x88Y\x12\xe2M]\xed\xd5\xe7\x9b\x9c\xaez"v\xfa\x97w\xc1`\xf2\xfdp\xc9G\x0f\xe5;\xe7_\xf4]C\xae~\xf6\xdd\xe3\xfan\x93;HL\x9cy\xc5\x11\x01tE\x02#\x95\x1c\x06\x16\x172\xe4P\xee\x92\x90\x06\x13\x01\xcd\x94\xc9D\xf0\x02\x82d\xa6\x1c\x80\x98\xfa\x0b\xbd\xf2\x0c\xb9)\x15\xce\xad>9\x7fE,\x83\x86N^\xd2%\x12\x14\x8a\xb0\x0c\x05!\x17r\xe3\xef\xef\x93jw\x8c\xd7\xfa,\x81m\x84T2d\xd5\x17\xcaC\x89\xc1=3rC\xd8T%\xf3\xae\xda&\x0b\x85\xdb\xe2T\xcd\xbb\x1a\xbe&`K\xc3zn\x9d-\'\xff\xdb^\xd4=\xb4\x17=F\xf3\xa3\x99\xe0\x1e\xb3\x87s\x9bz\xb8\xc2E\xac\xffX\xd6\x1e\xf92\xdf9p\xdb:\xde\x03^\xe6\x13,C\xa4~\xc1}\x8a\x8a\x80\x11\xabb\xbe\xba\xafO\xf9%\x9c;\xb4{\xf1\x81 \x9b\xfc\xd6\xdb\xa4\xf6\xdd\xe0\x0c|\xd4\xabZ\xa5d+\x11?K\x07|\x1f\x92\x06c\x8c[\xf44_\x8f\x14b\xad\xa6\xb1\xad\xc6\xda1\x0cy\x80X\xf3\x0c\xa1f8\xdf\x87E\x9a\x1a3\xd5\x8b\xac9\x8d\noA\xd5@\xe5?\xdb\xd4\rh\xf6\r4\x1c\x91\x05^1\x99\xb66\xa3\xe4N\n<\xdc\xfe\xef\r\xb0\xc2\xc4\x8e\xe1\xed\x8b\xbf\x01PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\x83\xc0c\x06\x9c\x01\x00\x00\x14\x04\x00\x00\x18\x00\x00\x00xl/worksheets/sheet1.xml}\x94\xddN\xeb0\x0c\xc7_\xa5\xca\x03\x90\xad[\x0bBm%\x06Bp\x81\x84@\xe7\x9cK\x94\xb5\xee\x1a\x91\x8f\x92x+\xbc\xfdI\xc2\x08e\xa2\xbd\xaa\xed\xc4\xbf\xbf\xdd8)\x06m^m\x07\x80\xc9\xbb\x14\xca\x96\xa4C\xec/)\xb5u\x07\x92\xd93\xdd\x83r+\xad6\x92\xa1s\xcd\x8e\xda\xde\x00kB\x92\x144],r*\x19W\xa4*B\xec\xd1T\x85\xde\xa3\xe0\n\x1eMb\xf7R2\xf3\xb1\x01\xa1\x87\x92,\xc9W\xe0\x89\xef:\x0c\x01Z\x15=\xdb\xc13\xe0\x9f\xde%8\x97FN\xc3%(\xcb\xb5J\x0c\xb4%\xb9Z^n\xf2\x90\x11v\xfc\xe50\xd8\x91\x9d\xf8f\xb6Z\xbfz\xe7\xbe)\xc9\xc2\xd7\x04\x02j\xf4\x08\xe6>\x07\xb8\x06!<\xc9U\xf2v\x84\x92oQ\x9f9\xb6\xbf\xf0\xb7\xa1\x7fW\xde\x96Y\xb8\xd6\xe2\x1fo\xb0+\xc9\x05I\x1ah\xd9^\xe0\x93\x1e\xee\xe0\xd8S\xf6]\xe2\rCV\x15F\x0f\x89\xf1\xcdVE\xed\x8d\xa0\x1e\x9aw\xdb\xb9\xf2\xbf\xea\x19\x8d[\xe5N\x0f+\x8e _xSPt\xa5\xf8\x10\xad\x8f\x89\x9b\xf9D\xc5$\xfc\xcc\xa2N:\xea\xa7Q?\r\x00\x7fd\x87jY\xd0\xc3X"\x9d\x80\xb3\x19\xf2*\x92W#rzB^M\x90\xb73\xe4u$\xafG\xe4\xd5\ty=A\xaeg\xc8Y$g#\xf2\xfa\x84\x9cM\x90\x9b\x19r\x1e\xc9\xf9\x88\x9c\x9d\x90\xf3\t\xf2\xaf\'HG\xd3\xe4o\xcb\x033;\xael"\xa0u\x90\xc5\xd9\xb9\xab\xd3|\x8e\xdf\xa7\x83\xba\x0fs\xb2\xd5\x88Z\x06\xb3s\xb7\x16\x8c\xdf\xe0\xd6[\xad1:~\xfc\xe3CP\xfd\x07PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xa8\xe7\x15\xb1\x9a\x01\x00\x00\xce\x03\x00\x00\x18\x00\x00\x00xl/worksheets/sheet2.xml}\x93aO\xc3 \x10\x86\xffJ\xc3\x0f\x90\xae\xdb\xaa1m\x13\xa71\xfa\xc1d\xd1\xa8\x1f\rk\xaf+\x19\x94\n\xb7U\xff\xbd\x80\x13\xd9\xcc\xfcT\x8e\xf7\xee\xb9\xf7\n\x14\xa3\xd2\x1b\xd3\x01`\xf2!EoJ\xd2!\x0e\x97\x94\x9a\xba\x03\xc9\xcc\x99\x1a\xa0\xb7J\xab\xb4dhC\xbd\xa6f\xd0\xc0\x1a_$\x05\xcd\xd24\xa7\x92\xf1\x9eT\x85\xdf[\xea\xaaP[\x14\xbc\x87\xa5N\xccVJ\xa6?\x17 \xd4X\x92\t\xf9\xd9x\xe4\xeb\x0e\xfd\x06\xad\x8a\x81\xad\xe1\t\xf0y\xb0\x056\xa4\x81\xd3p\t\xbd\xe1\xaaO4\xb4%\xb9\x9a\\.r_\xe13^8\x8c&Z\'n\x98\x95R\x1b\x17\xdc7%I\x9d\'\x10P\xa3C0\xfb\xd9\xc15\x08\xe1H\xd6\xc9\xfb\x1eJ~\x9b\xba\xcax\xfd\x83\xbf\xf5\xf3[{+f\xe0Z\x89W\xde`W\x92\x0b\x924\xd0\xb2\xad\xc0G5\xde\xc1~\xa6\xf9\xaf\xc5\x1b\x86\xac*\xb4\x1a\x13\xed\x86\xad\x8a\xda-|w?\xbcM\xe7\xbd\xfbUO\xa8\xad\xcam?\xac8\x82|\xe3MA\xd1Zq[\xb4\xde\x17.\xfe/\x1c4\xaf\xe1\xb0\x8c\xda\xde\xc1@\x16\x0cd\x9e\xe0\xcelWM\n\xba\x8b{\x1chi\x9a\x06\xf9\x805\r\xaci\x94\x9f\x1d\xb1b\xed\xe2\x14j\x16P\xb3(}z\x84:\xd0N\xda\x9a\x07\xd6<\xca\x9f\x1d\xb1b-K\xa7\'Xy`\xe5Q\xfe\xfc\x88\x15k\xf9__4\xba\x07\xee\x9e?0\xbd\xe6\xbdI\x04\xb4\xb6,=;\xb7^\xf4\xf7\xc5\xf9\x0eP\r\xfe\x84W\nQI\xbf\xec\xec{\x03\xed\x12\xac\xde*\x85!p\x177<\xe1\xea\x0bPK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xf7\xf6\x8f\t\xa7\x02\x00\x00m\x0b\x00\x00\r\x00\x00\x00xl/styles.xml\xddV\xdb\x8e\x9b0\x10\xfd\x15\xc4\x07\x94MPQ\xa8B\xa46\xd2J\x95\xdaj\xa5\xdd\x87\xbe\x9a`\x82%_\xa81\xabd\xbf\xbe3\xb6\x13\x92\xec\x0e\xdd\xf6\xb1\xa0\x84\xf1\x1c\x9f\xb9;d=\xb8\xa3\xe4\x8f\x1d\xe7.9(\xa9\x87*\xed\x9c\xeb?e\xd9\xb0\xeb\xb8b\xc3\x07\xd3s\rHk\xacb\x0e\x96v\x9f\r\xbd\xe5\xac\x19\x90\xa4d\xb6\xbc\xbb+2\xc5\x84N7k=\xaa{\xe5\x86dgF\xed\xaa\xf4.M\xb2\xcd\xba5zR-\xd3\xa0\x80\xbdL\xf1\xe4\x99\xc9*\xdd2)j+\xc2f\xa6\x84<\x06\xfd\xd2kvF\x1a\x9b8\x88\x86W\xe9\xc2\xab\x86\x97\xb0a\x11\x97\x18j\xb4\xa5\x846\xd6k\xb3\xe0&|\xd7\x91p\x89\xf8\xc7\x00;\x84\x94\xd7\xf1\x81b\xb3\xee\x99s\xdc\xea{X\x04\x92\xd7\xbe\xc6\xa2\xfct\xec!\xbe\xbde\xc7\xc5\xf2cz\xc1\xf0\x0fpS\x1b\xdbp{\xe5(\xa86k\xc9[\x87\x0c+\xf6\x9d\x17\x9c\xe9\xf1Q\x1b\xe7\x8cB\xa9\x11lo4\x0b\x91\x9chWt\xdf\xc8*u\x1d4b\xb2u\xabE\xc3\xb7\xba\xe8\xe5V}v\x13\x05Ha\xc7\xa5|\xc4m?\xdbs\x1e\x0b\xc8\xe3\xd0&\xa1\xf3_\x1b\xdft,\xecI\x84\xe4\xa3\x18\xcc\xc4\x05:\xb84\x17\x8c_\xd8]\xfe\x9b\xdd^<\x1b\xf7e\x84\x8c\xb4_\xff\x1a\x8d\xe3\x0f\x96\xb7\xe2\xe0\xd7\x87v\n\x802\xbf \xcc\x83\x9e\xf5\xbd<~\x96b\xaf\x15\x0f\xd9\xbf\xdb\xe3f\xcdN\xbc\xa43V\xbc\x807\x9c\xc9\x1d(8\x8c\xec3\xb7N\xecP\x03M\n\x05:\xb4\xb1J\xe7\x02\xf9r]\xd5\xfe\xacM\xf0@U\xe9\x0f<\xa8\xf2"\xd1z\x14\xd2\t\x1dW\x9dh\x1a\xae_\xb7\x00\xec;V\xc3O\xc1\x95\x03\xd8\xd5\xf0\x96\x8d\xd2=\x9d\xc1*\x9d\xe4\xef\xbc\x11\xa3*\xcf\xbb\x1e\xb0\x16q\xd7$\x7f\xc3Q\\\x14\xd3i\x06gB7\xfc\xc0\x9bm\\\xda}\xed\xc5\x04\x04p\x1b\xaf0\xc87\xd0\xbd\xbf\x08\x88d\x05\x90\x80\x10$}\x91a\x90\xac\xc0#}\xfd\x8fy\xad\xe8\xbc\x02HF\xb8z\x1bZ\xd1\xac\x15\xcd\n\xbc7\xa1\xad\xbfI_\x04\xab\x84\x8bH\xb9,\xf3\xbc(\xc8\xf2n\xb7o\x87\xb1%kX\x14\xf8!\x0c\x92\x11"\x87\xf4\x85\xde\xfe\xb6\xf23\x03036\x7f\x98\r\xb2\xcb\xb3cC\xa6<3\xa2d\xca3\x95G\x88\xa8!r\xca\x92\x18\x00\xd2\x17r\xc8\xa6\x90\x13\x85A\x10\xbep\xd4\x08V\x9ec\x9f\xc9\x08\xc9c>\x03\x95%\t\xe1\x90\x12\xd3[\x14T\xa1\n\xbc\x89~\x91\x87(\xcf\xcb\x92\x80\x10$\xc2\xc8s\x12\xc2\x03;\x03\x91a` $\x94\xe7\xe1Ez\xf3>\xcbN\xef\xb9l\xfa\x83\xbd\xf9\rPK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xb7G\xeb\x8a\xc0\x00\x00\x00\x16\x02\x00\x00\x0b\x00\x00\x00_rels/.rels\x9d\x92Kn\x021\x0c@\xaf\x12e_L\xa9\xc4\x021\xac\xd8\xb0C\x88\x0b\xb8\x89\xe7\xa3\x99\xc4\x91c\xc4\xf4\xf6\x8d\xd8\xc0 h\x11K\xff\x9e\x9e-\xaf\x0f4\xa0v\x1cs\xdb\xa5l\xc60\xc4\\\xd9V5\xad\x00\xb2k)`\x9eq\xa2X*5K@-\xa14\x90\xd0\xf5\xd8\x10,\xe6\xf3%\xc8-\xc3n\xd6\xb7Ls\xfcI\xf4\n\x91\xeb\xbas\xb4ew\n\x14\xf5\x01\xf8\xae\xc3\x9a#JCZ\xd9q\x803K\xff\xcd\xdc\xcf\n\xd4\x9a\x9d\xaf\xac\xec\xfc\xa75\xf0\xa6\xcc\xf3\xf5 \x90\xa2GEp,\xf4\x91\xa4L\x8bv\x94\xaf>\x9e\xdd\xbe\xa4\xf3\xa5cb\xb4x\xdf\xe8\xff\xf3\xd0\xa8\x14=\xf9\xbf\x9d0\xa5\x89\xd2\xd7E\t&o\xb0\xf9\x05PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[Wf!1\xaaB\x01\x00\x00n\x02\x00\x00\x0f\x00\x00\x00xl/workbook.xml\x8d\x91aK\xc30\x10\x86\xffJ\xc9\x0f\xb0]\xd1\x81c\xf5\x8bC\x1d\x88\x8a\x93}\x1dis]\x8f%\xb9\x92\\7\xdd\xaf7M\xa9\x16\x14\xf1Sr\xef\x1dO\xde\xf7\xb2<\x91;\x94D\x87\xe4\xddh\xeb\x17\xae\x10\rs\xbbHS_5`\xa4\xbf\xa0\x16l\xe8\xd5\xe4\x8c\xe4P\xba}Ju\x8d\x15\xac\xa8\xea\x0cXN\xf3,\x9b\xa7\x0e\xb4d$\xeb\x1bl\xbd\x18h\xffa\xf9\xd6\x81T\xbe\x01`\xa3\x07\x94\x91h\xc5\xcdrt\xf6\xe2\x92tZ\x11C\xd5\xbf\xd4\xab\xbd\xb2E8\xf9\xef\x81\xbeL\x8e\xe8\xb1D\x8d\xfcQ\x88x\xd7 \x12\x83\x16\r\x9eA\x15"\x13\x89o\xe8\xf4@\x0e\xcfdY\xeaM\xe5H\xebB\xcc\x86\xc6\x16\x1cc\xf5C\xde\xf46\xdfd\xe9\xa3\xc2\xb2|\xed3\x17b\x9e\x05`\x8d\xces\x9c\x88|\x19L\x1e!\x0c\x0fU\xc7t\x87\x9a\xc1\xad$\xc3\xbd\xa3\xaeE\xbb\x8f\x98\x10#\x9d\xe4\x88\xab\x18\xcf\xc4J\x03\x85P\xf5\x8e\xc1\xf3.\xda\x08\xf2Z\r\x968\xb0&\x01\xdd\x02C\xc3\xad\xd5@\xfd\x8d\x90O\x08\xf9\x1f\x84|\xf05\x9aQP\xa3\x05\xf5\x14X\xbeo\x84\xd5T\xe1_\xfa#z\xc9/\xaff\xd7a\x05\x9d\xd6\xb7A{\xb6\x8f$\xd5W\xba\xf1kn>\x01PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xab^r.\xb4\x00\x00\x00\x8d\x02\x00\x00\x1a\x00\x00\x00xl/_rels/workbook.xml.rels\xc5\x92M\n\x830\x10F\xaf\x12r\x00Gm\xe9\xa2\xa8\xabn\xdc\x16/\x10t\xfc\xc1\xc4\x84\xcc\x94\xea\xed+\xbaP\xa1\x8bn\xa4\xab\xf0M\xc8\xfb\x1eL\x92\'j\xc5\x9d\x1d\xa8\xed\x1c\x89\xd1\xe8\x81R\xd92\xbb;\x00\x95-\x1aE\x81u8\xcc7\xb5\xf5F\xf1\x1c}\x03N\x95\xbdj\x10\xe20\xbc\x81\xdf3d\x96\xec\x99\xa2\x98\x1c\xfeB\xb4u\xdd\x95\xf8\xb0\xe5\xcb\xe0\xc0_\xc0\xf0\xb6\xbe\xa7\x16\x91\xa5(\x94o\x90S\t\xa3\xde\xc6\x04\xcb\x11\x053Y\x8a\xbcJ\xa5\xcf\xabH\n\xf8\xb7Q|0\x8a\xcf4"\x9e4\xd2\xa6\xb3\xe6C\xff\xe5\xcc~\x9e\xdf\xe2V\xbf\xc4ux\\\xcbu\x91\x80\xc3\xef\xcb>PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xa5\xe1\x1bX\x1f\x01\x00\x00`\x04\x00\x00\x13\x00\x00\x00[Content_Types].xml\xc5T\xcbN\xc30\x10\xfc\x95\xc8\xd7*v\xe9\x81\x03jz\xa1\\\xa1\x07~\xc0$\x9b\xc6\x8a_\xf2nK\xfa\xf7l\x12Z\tTZ\xaa q\x89\x15\xef\xec\xccx\xc7\xf2\xf2\xf5\x10\x01\xb3\xceY\x8f\x85h\x88\xe2\x83RX6\xe04\xca\x10\xc1s\xa5\x0e\xc9i\xe2\xdf\xb4UQ\x97\xad\xde\x82Z\xcc\xe7\xf7\xaa\x0c\x9e\xc0SN=\x87X-\xd7P\xeb\x9d\xa5\xec\xa9\xe3m4\xc1\x17"\x81E\x91=\x8e\xc0^\xab\x10:FkJM\\W{_}S\xc9?\x15$w\x0e\x18lL\xc4\x19\x03D\xa6\xceJ\x0c\xa5\x1f\x15\x8e\x8d/{H\xc9T\x90mt\xa2g\xed\x18\xa6:\xab\x90\x0e\x16P^\xe68\xe32\xd4\xb5)\xa1\n\xe5\xceq\x8b\xc4\x98@W\xd8\x00\x90\xb3r$\x9d]\x91&\x1e2\x8c\xdf\xbb\xc9\x06\x06\x9a\x8b\x8a\x0c\xdd\xa4\x10\x91SKp\xbb\xde1\x96\xbe;\x8fL\x04\x89\xcc\x95C\x9e$\x99{\xf2\t\xa1O\xbc\x82\xea\xb7\xe2<\xe1\xf7\x90\xda!\x13T\xc32}\xcc_s>\xf1\xdfjd\xf1\x9fF\xdeBh\xff\xfa\xc2\xf7\xabt\xda\xf8\x93\x015<,\xab\x0fPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[WFZ\xc1\x0c\x82\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x00\x00\x00\x00docProps/app.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xdb\xca)$\xeb\x00\x00\x00\xcb\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\xb0\x00\x00\x00docProps/core.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\x99\\\x9c#\x10\x06\x00\x00\x9c\'\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\xca\x01\x00\x00xl/theme/theme1.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\x83\xc0c\x06\x9c\x01\x00\x00\x14\x04\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x81\x0b\x08\x00\x00xl/worksheets/sheet1.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xa8\xe7\x15\xb1\x9a\x01\x00\x00\xce\x03\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x81\xdd\t\x00\x00xl/worksheets/sheet2.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xf7\xf6\x8f\t\xa7\x02\x00\x00m\x0b\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\xad\x0b\x00\x00xl/styles.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xb7G\xeb\x8a\xc0\x00\x00\x00\x16\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\x7f\x0e\x00\x00_rels/.relsPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[Wf!1\xaaB\x01\x00\x00n\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01h\x0f\x00\x00xl/workbook.xmlPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xab^r.\xb4\x00\x00\x00\x8d\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\xd7\x10\x00\x00xl/_rels/workbook.xml.relsPK\x01\x02\x14\x03\x14\x00\x00\x00\x08\x00\x1d\xa7[W\xa5\xe1\x1bX\x1f\x01\x00\x00`\x04\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x01\xc3\x11\x00\x00[Content_Types].xmlPK\x05\x06\x00\x00\x00\x00\n\x00\n\x00\x84\x02\x00\x00\x13\x13\x00\x00\x00\x00'
만약 bio.read()로 객체를 읽기 전에 bio.seek(0)를 써주면 위처럼 뭔가 데이터가 출력됩니다.
우리가 눈으로 저걸 해석하기는 어렵겠지만 어쨌든 생성한 xlsx 파일의 내용을 의미합니다.
BytesIO로 xlsx file 생성하는 또다른 참고 예시 = https://stackoverflow.com/questions/59348309/create-an-excel-file-from-bytesio-using-python
BytesIO 객체로 xlsx 파일을 생성하는 것을 알아봤으니
이제 BytesIO 객체로 생성된 xlsx 파일을 다시 읽어서 DataFrame으로 읽어오는 방법을 봐봅시다.
import pandas as pd
from io import BytesIO
df_test_1 = pd.DataFrame({
'item_id': [1, 2, 3, 4, 5],
'name': ['a', 'b', 'c', 'd', 'e']
})
df_test_2 = pd.DataFrame({
'item_id': [1, 2, None, 4, None, None, 3],
'price': [1000, 800, 3000, None, ' ', None, None],
'empty_col': [None, None, None, None, None, None, None],
None: [None, None, None, None, None, None, None],
None: [None, ' ', None, None, None, None, None]
})
bio = BytesIO() # ByesIO 객체 생성
xlsx_writer = pd.ExcelWriter(bio, engine='openpyxl') # ExcelWirter를 BytesIO 객체를 대상으로 생성
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1') # xlsx에 원하는 sheet 생성
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2') # xlsx에 원하는 sheet 생성
xlsx_writer.save() # BytesIO 메모리에 xlsx 정보 저장
bio.seek(0)
xlsx_file = bio.read() # 방금 저장했던 BytesIO() 객체에 담긴 내용을 읽어오기
df_test_1 = pd.read_excel(xlsx_file, sheet_name='df_test_1') # BytesIO 객체의 형태로 저장된 xlsx 파일을 읽어서 DataFrame으로 만들기
df_test_2 = pd.read_excel(xlsx_file, sheet_name='df_test_2') # BytesIO 객체의 형태로 저장된 xlsx 파일을 읽어서 DataFrame으로 만들기
print(df_test_1)
print(df_test_2)
-- Result
item_id name
0 1 a
1 2 b
2 3 c
3 4 d
4 5 e
item_id price empty_col Unnamed: 3
0 1.0 1000 NaN NaN
1 2.0 800 NaN
2 NaN 3000 NaN NaN
3 4.0 NaN NaN NaN
4 NaN NaN NaN
5 NaN NaN NaN NaN
6 3.0 NaN NaN NaN
위 예시를 봅시다.
일단 코드의 윗 부분은 기존처럼 DataFrame을 BytesIO 객체로 생성하는 부분입니다.
bio = BytesIO() # ByesIO 객체 생성
xlsx_writer = pd.ExcelWriter(bio, engine='openpyxl') # ExcelWirter를 BytesIO 객체를 대상으로 생성
df_test_1.to_excel(xlsx_writer, index=False, sheet_name='df_test_1') # xlsx에 원하는 sheet 생성
df_test_2.to_excel(xlsx_writer, index=False, sheet_name='df_test_2') # xlsx에 원하는 sheet 생성
xlsx_writer.save() # BytesIO 메모리에 xlsx 정보 저장
bio.seek(0)
xlsx_file = bio.read() # 방금 저장했던 BytesIO() 객체에 담긴 내용을 읽어오기
df_test_1 = pd.read_excel(xlsx_file, sheet_name='df_test_1') # BytesIO 객체의 형태로 저장된 xlsx 파일을 읽어서 DataFrame으로 만들기
df_test_2 = pd.read_excel(xlsx_file, sheet_name='df_test_2') # BytesIO 객체의 형태로 저장된 xlsx 파일을 읽어서 DataFrame으로 만들기
print(df_test_1)
print(df_test_2)
핵심은 위 부분입니다.
방법은 굉장히 간단합니다.
BytesIO 객체를 그냥 read_excel method로 읽어버리면 되죠.
- 추가
간혹 위 방식에서 에러가 발생하는 경우가 있는데 그 중 하나는 openpyxl version error입니다.
df_test_1 = pd.read_excel(xlsx_file, sheet_name='df_test_1')
df_test_2 = pd.read_excel(xlsx_file, sheet_name='df_test_2')
위처럼 read_excel() method는 일반적으로 아래와 동일합니다.
df_test_1 = pd.read_excel(xlsx_file, sheet_name='df_test_1', engine='openpyxl')
df_test_2 = pd.read_excel(xlsx_file, sheet_name='df_test_2', engine='openpyxl')
engine을 openpyxl을 쓴다는 의미이죠.
근데 간혹 openpyxl의 version이 매우 낮거나 pandas version과 호환이 되지 않으면 openpyxl의 version을 upgrade하라는 등의 error가 발생할 수 있습니다.
이런 경우 openpyxl의 기능을 이용하여 직접 엑셀을 조작하여 DataFrame으로 만들어야하는데 관련된 방법은 아래 링크를 참고하면 됩니다.
'Python > Python ETC' 카테고리의 다른 글
PyCharm에서 환경변수 설정, Interpreter별 환경변수 설정, Custom library 경로 설정 (2) | 2024.02.08 |
---|---|
Python openpyxl : Python에서 Excel 다루기, BytesIO xlsx 객체 읽어오기 (0) | 2023.12.13 |
Python io : StringIO (comma separate csv type string 생성, DataFrame을 csv type string으로 변환하기) (0) | 2023.10.18 |
Python requests : GET/POST 방식 요청, API 사용, curl, requests (0) | 2023.09.13 |
Python API : Python으로 API 만들기 (FastAPI, Flask) (0) | 2022.12.04 |