블로그나 티스토리를 쓸 때는 당연히 코드 복사 기능이 있어 불편하지 않았는데, WordPress로 바꾸니 복사 아이콘도 없고, Ctrl + A키를 누르면 화면 전체가 선택돼서, 찾아보니 Copy Anything to Clipboard(한글명 클립보드에 복사)란 플러그인이 있습니다.
1. Copy Anything to Clipboard
가. 플러그인 추가
알림판에서 플러그인 > 플러그인 추가를 클릭하고
플러그인 검색 란에 ‘copy anything’이라고 입력하면 한글로 ‘클립보드에 무엇이든 복사하기’로 표시되고, 왼쪽 아이콘 안에 ‘Copy Anything to Clipboard’가 표시됩니다.
지금은 오른쪽 버튼명이 설치가 되고 활성화돼서 ‘활성’이라고 되어 있는데, 설치가 안되어 있다면 오른쪽 플러그인 처럼 ‘지금 설치’라고 되어 있을 것이므로 ‘지금 설치’ 버튼을 눌러 설치합니다.
나. 설정 – 실패 => ‘다. 설정 – 성공’으로 건너뛰어도 됩니다.
플러그인 설치를 하면 아래와 같이 설정 화면이 나옵니다.
처음에는 뭔지 모르고 그냥 글쓰기로 넘어가서 글을 작성하고,
왼쪽 위 블록 삽입기를 누르고, 맨 아래로 내려가서 ‘클립보드에 무엇이든 복사하기’ 그룹의 ‘복사 아이콘’을 눌러 코드 위에 ‘복사 아이콘’을 추가한 후
보기 > 새 탭에서 미리 보기를 눌러
글 위의 복사 아이콘을 누르면
‘Copied’라고는 표시되는데, 메모장에 붙여 넣기를 하면
아무 것도 붙여지지 않습니다.
다. 설정 – 성공
(1) 설정
‘클립보드에 무엇이든 복사하기’ 플러그인을 설정하기 위해
알림판 > 설정 > ‘클립보드에 복사’를 누른 다음
설정을 하는데, 이미 설정이 되어 있으므로, ‘code 복사’ 아래의 편집을 눌러보겠습니다.
그러면 아래와 설정된 내용이 나오는데,
Post Title은 ‘code 복사'(각자 알맞게 설정)이고,
설정(Settings)의 의미는 pre 태그(Selector)가 있으면
Default 형식(글 복사)으로 복사하는데,
모양은 아이콘이 아닌 버튼 모양이고,
버튼의 설명문은 Copy to Clipboard, Copied 등입니다.
설정을 다 했으면 아래 Save Changes 버튼을 눌러 저장합니다. 위에서는 Save Changes가 비활성화되어 있었는데, 설정을 바꾸면 활성화됩니다.
(2) Style – 아이콘과 버튼
버튼 모양이 아닌 아이콘 모양으로 하면
코드 블록의 배경색이 회색인 경우 인지가 잘 안되어
버튼 모양으로 하는 것이 구분이 잘됩니다.
(3) Format – Default, Google Docs, Email
참고로 Format은 Default, Google Docs, Email 형식이 있습니다.
(4) 적용 결과
이제 작성된 글을 보면 코드뿐만 아니라 정형화된 형식으로 작성된 부분에도 ‘Copy To Clipboard’가 윗 부분에 추가된 것을 알 수 있고,
이미 작성된 글 전체에 일괄적으로 적용된 것을 알 수 있습니다.
3. 상세한 설명 사이트
코드 말고, 다른 설정을 하고 싶으면 아래 사이트의 ‘continue reading’를 눌러서 읽어보기 바랍니다.
비어 있는 셀은 엑셀에서 주의해야 할 사항입니다. Month함수를 사용하면 1로 표시되기 때문입니다. 왜냐하면 1900-01-00이기 때문에 일이 0, 월은 1이 됩니다. 따라서, 집계할 때도 Month를 계산할 때 공백을 제외하도록 추가적인 조건을 주거나 날짜를 지정해야 합니다.
러스트의 경우 처음에 명령 프롬프트 창에서 포트를 열어놓고 Cargo run을 하라고 하여 Python은 포트를 열 필요없이 잘 접속되는데 해서 비교하게 되었습니다. 그리고, 보면 파이썬은 편리한 상태를 만들어 놓았는데, Rust는 처음부터 내가 만들어가야 하는 상황입니다.
Chromedriver가 Path에 있다면 그냥 실행하면 되는데, path가 설정되어 있지 않아, chromedriver.exe가 있는 폴더로 이동해서 실행했습니다.
(2) 브라우저 열기 Rust 코드
(가) Cargo.toml
[dependencies]
thirtyfour = "0.36.1"
tokio = { version = "1", features = ["full"] }
thirtyfour와 tokio 라이브러리를 가져와야 합니다.
(나) main.rs
use thirtyfour::prelude::*;
use tokio;
#[tokio::main]
async fn main() -> WebDriverResult<()> {
// 이미 chromedriver가 9515 포트에서 실행 중이라고 가정
let driver = WebDriver::new("http://localhost:9515", DesiredCapabilities::chrome()).await?;
// 페이지 접속
driver.get("https://www.rust-lang.org").await?;
// 타이틀 가져오기
let title = driver.title().await?;
println!("Page title: {}", title);
// 종료
driver.quit().await?;
Ok(())
}
코드이 내용은 port가 열려 있기 때문에 다시 열 필요는 없고, 9515 포트로 driver를 설정한 다음, rust-lang.org에 접속한 후 title을 가져와서 화면에 출력하는 것입니다.
문제 없이 코드가 실행되고, title이 표시됩니다.
나. 코드로 포트 열기 방식
명령 프롬프트에서 포트를 연 다음 Cargo run을 한다는 것이 이상하므로 Rust에서 포트를 열고, 실행하려면 아래와 같이 코드를 작성하면 됩니다.
Cargo.toml은 동일하고,
main.rs만 아래와 같이 수정하면 됩니다.
use std::process::Command;
use thirtyfour::prelude::*;
use tokio;
#[tokio::main]
async fn main() -> WebDriverResult<()> {
// 실행파일이 있는 디렉토리 경로
let exe_dir = std::env::current_exe()
.unwrap()
.parent()
.unwrap()
.to_path_buf();
let chromedriver_path = exe_dir.join("chromedriver.exe");
println!("chromedriver 경로: {}", chromedriver_path.display());
// chromedriver 실행
let mut child = Command::new(&chromedriver_path)
.arg("--port=9515")
.spawn()
.expect("chromedriver 실행 실패");
// WebDriver 클라이언트 연결
let caps = DesiredCapabilities::chrome();
let driver = WebDriver::new("http://localhost:9515", caps).await?;
driver.get("https://www.rust-lang.org").await?;
println!("현재 페이지 타이틀: {}", driver.title().await?);
// 브라우저 닫기
driver.quit().await?;
// chromedriver 프로세스 종료
child.kill().ok();
Ok(())
}
use std::process::Command;가 추가되었습니다.
main에서 먼저 chromedriver_path를 설정하고,
Command::new를 이용해 포트를 연 다음 child에 저장하고,
caps는 python Selenium에서 사용하는 ChromeOptions 역할입니다. 기본적인 옵션만 설정하는 것입니다. caps.add_arg(“–headless”)?; 등을 추가해서 옵션을 추가할 수 있습니다.
그리고, WebDriver::new로 http://localhost:9515라고 9515포트를 이용해 localhost를 연 다음
driver.get로 https://www.rust-lang.org를 연 다음
driver.title().await?로 title을 가져와서 화면에 출력합니다.
아래는 Visual Studio Code에서 Run한 장면입니다.
Compile과 실행 잘 되고, ChromeDriver was started successfully on port 9515.와
현재 페이지 타이틀 : Rust Programming Language라고 잘 나옵니다.
2. Python을 이용한 웹 접속
가. chrome_connect.py
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
import os
def main():
# 실행 파일이 있는 디렉토리 기준으로 chromedriver.exe 찾기
exe_dir = os.path.dirname(os.path.abspath(__file__))
chromedriver_path = os.path.join(exe_dir, "chromedriver.exe")
# chromedriver.exe 고정 경로
# chromedriver_path = r"C:\android\chromedriver.exe"
# print(f"chromedriver 경로: {chromedriver_path}")
# chromedriver 실행 (포트 지정 없이 내부적으로 관리)
service = Service(chromedriver_path)
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(service=service, options=options)
try:
driver.get("https://www.rust-lang.org")
print(f"현재 페이지 타이틀: {driver.title}")
finally:
driver.quit()
if __name__ == "__main__":
main()
Python은 Cargo.toml과 같은 설정이 필수가 아니고,
바로 python code를 위와 같이 작성하면 됩니다.
실행 결과는 아래와 같습니다.
나. 코드 내용
from selenium import webdriver from selenium.webdriver.chrome.service import Service import os
필요한 selenium과 os 라이브러리를 불러옵니다.
# 실행 파일이 있는 디렉토리 기준으로 chromedriver.exe 찾기
exe_dir = os.path.dirname(os.path.abspath(__file__))
chromedriver_path = os.path.join(exe_dir, "chromedriver.exe")
# chromedriver.exe 고정 경로
# chromedriver_path = r"C:\android\chromedriver.exe"
실행 파일이 있는 폴더의 chromedriver.exe를 chromedriver_path로 설정합니다.
주석 처리한 것처럼 고정 경로로 지정할 수도 있습니다. 여러 프로그램에서 공통적으로 사용할 수 있으므로 PC에서만 작업한다면 이것이 편할 수 있습니다.
print(f"chromedriver 경로: {chromedriver_path}")
chromedriver_path를 화면에 출력합니다.
# chromedriver 실행 (포트 지정 없이 내부적으로 관리) service = Service(chromedriver_path) options = webdriver.ChromeOptions()
Service 메소드를 이용해 service를 생성하고, webdriver.ChromeOptions()로 크롬 설정을 기본으로 합니다.
등록번호별로 운행, 충전중, 완충과 구동시간이 표시된 데이터를 기준으로 월별 최소, 최대, 평균 충전 사용 시간을 구하려고 합니다. 그런데, 운행과 충전중, 완충 데이터가 연속되는 경우도 있고, 최초 충전의 경우는 이전 충전 기록이 없음에 따라 이들을 고려한 수식을 만들려고 합니다.
1. 문제
아래 표를 보면 A열이 구동시간, B열이 년-월, C열이 날짜, D열이 배터리 상태, E열이 등록번호, F열이 배터리 잔량, G가 최종시간으로 되어 있고,
오른쪽에 원하는 집계표 양식이 있습니다. 월별로 1회 충전 사용 시간의 최소, 최대, 평균 값을 구하는 것입니다.
2. 문제의 정의
문제를 풀려면 문제가 뭔지 알아야 합니다.
처음에는 완충이 왜 여러 번 나오지, 다른 차라서 그렇겠지 했는데, 차는 같은데 계속 꽂아 놓아서 10분 간격으로 완충이라고 표시되는 것이었다.
완충 시간이 연속될 경우 시간을 어떻게 구하는지 물어보니 첫번째 완충에서 이전 마지막 완충시간을 빼서 구한다고 한다.
완충이 아니라 충전중이다가 운행을 할 경우에도 최초 충전중 시간에서 이전 최종 완충 또는 충전중 시간을 뺀다
처음에는 충전중이었다가 완충이 되는 경우에 완충에서 이전의 충전중 또는 완충시간을 빼는 거라고 잘못 생각하고,
아래와 같은 경우 완충이 179행에 있고, 이전 충전중이 168행에 있으니 179행의 A열에서 168행의 A열을 빼니 1:49:35이고, 중간에 운행에서 충전중일 때는 게산 안하는 것인 줄 알았다.
그러나. 운행에서 충전중으로 바뀌는 시점에 충전중인 172행에서 168행을 빼는 것이 맞았다.
정리를 하면 운행에서 충전중 또는 완충으로 바뀔 때(신기하게 충전중을 거치지 않고 바로 완충 표시가 나옴) 운행 이전의 충전중 또는 완충 시간을 빼서 운행 시간을 구하는 것이다. => 기준 1
그리고, 이전 충전 기록이 없을 때 0으로 표시할 것이지, 아니면 최초 운행 시간을 기준으로 할 것인지 의문이 있는데, 0으로 표시하는 것보다는 최초 운행시간을 기준으로 하는 것이 맞다. => 기준 2
3. 해결방법
이제 문제와 기준을 알았으니 수식만 만들면 된다.
가. 텍스트로 된 날짜 데이터 변환하기
A2셀에서 A4셀까지 범위를 잡은 후 상태 표시줄을 보니 개수: 3이라고 표시된다. 날짜 형식이 아니라 텍스트이다.
(1) 날짜 시간 데이터 바꾸기
H2셀에 1이라고 입력하고 복사한 후 A2셀부터 맨 아래까지 선택한 후 마우스 오른쪽 버튼을 누른 후 선택하여 붙여넣기를 누르고(오른쪽 꺾기를 누르면 한번 더 선택하여 붙여넣기를 눌러야 하므로 불편),
곱하기를 누르고, 확인 버튼을 누른다.
그러면 모두 실수로 바뀌는데 날짜만 있으면 정수인데, 시간까지 있어서 실수가 되는 것입니다.
이제 A열의 표시형식을 yyyy-mm-dd hh:mm:ss로 바꿉니다.
그런데, 마우스 오른쪽 버튼을 누른 후 셀 서식을 선택하고 사용자 지정으로 들어가봐도 yyyy-mm-dd h:mm까지만 있고, hh:mm:ss는 없습니다. 그러면 형식 바로 아래에 있는 yyyy-mm-dd h:mm를
yyyy-mm-dd hh:mm:ss로 수정하면 됩니다. 형식을 수정하니 위의 보기도 바로 변경됩니다. 이제 확인 버튼을 누르면
A열은 날짜 표시 형식이 연-월-일 시:분:초로 바뀌었는데, B열과 C열은 여전히 실수입니다.
(2) 연-월 바꾸기
B2셀의 수식을 살펴보니 =LEFT(A2,7)이라고 문자열 기준으로 수식이 되어 있습니다.
따라서, 수식부터 Year와 Month 함수를 이용하거나 Text 함수를 이용해 수정해야 합니다.
Text 함수를 이용하면 =TEXT(A2,”yyyy-mm”)가 됩니다. 표시형식을 지정하는 것과 비슷합니다.
(3) 날짜(상세) 바꾸기
C2셀의 수식으 보면 =LEFT(A2,10)으로 문자열 기준으로 수식이 되어 있습니다.
이 때도 Text함수를 이용할 수 있는데, 이번에는 복잡하지만 Date 함수와 Year, Month, Day 함수를 이용해서 구해보겠습니다.
C2셀에 =DATE(YEAR(A2),MONTH(A2),DAY(A2))라고 입력하니 숫자가 아닌 날짜 표시형식으로 표시됩니다.
내용을 보니, 두번째 문단에 “Only local connections are allowed.”라고 나오고,
Starting ChromeDriver 140.0.7339.80 (670b6f192f4668d2ac2c06bd77ec3e4eeda7d648-refs/branch-heads/7339_41@{#3}) on port 63428 Only local connections are allowed. Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe. ChromeDriver was started successfully on port 63428.
네번째 문단에 “ChromeDriver가 성공적으로 63428 포트에서 시작되었다”하는데, 구글 사이트에 접속하지 못하고 여기서 멈춰있습니다.
그런데 오전에는 아래와 같은 메시지도 나왔는데,
PdhAddEnglishCounter failed for ‘\Hyper-V Hypervisor Logical Processor(_Total)\% Total Run Time’
이것은 관리자 권한으로 명령 프롬프트를 실행하고
lodctr /r라고 실행하니
Info: ??? ?? ?????? ?? ??? ??? ?? ??????. 라고 이상한 문자로 표시됐지만, ChatGPT에게 물어보니 한글 인코딩 문제이고, “정상 완료 메시지”라고 합니다.
이렇게 한글이 깨져서 보이는 건 메시지 출력 시 콘솔 인코딩 문제예요. 내용 자체는 “성능 카운터 레지스트리를 다시 빌드했습니다” 같은 정상 완료 메시지인데, 한글이 깨져서 표시된 거예요.
그래서 더 이상 위 PdhAddEnglishCounter 에러 메시지는 안나오는 듯 합니다.
3. ChromeDriverManager로는 된다.
계속 ChatGPT에게 물어봐도 해결되지 못하고 있었는데, chromedrive 버전을 확인하라고 해서 확인하니 135라고 표시돼서, 그러면 “ChromeDriverManager를 실행하면 어떻겠냐”고 제안해서 해보니 된다.
하루 묶은 체증이 다 내려가는 느낌이다.
그렇게 안되더니 이럴 수가…
그래서 ChromeDriverManager로 인스톨한 chromedriver.exe와 크롬 드라이버 다운로드 사이트에서 받은 파일을 비교해보니 파일 사이즈가 다릅니다. 어찌 이럴 수가 있죠?
작은 것(chromedriver2.exe라고 파일명 변경)이 제대로 돌아가는 파일이고, 문제가 있는 파일이 chromedriver.exe입니다.
claude desktop에 pyhub.mcptools를 설치한 뒤, claude와 엑셀과 연동하면서 clade에게 문제를 풀어달라고 하고, 잘못된 부분이 있으면 수정해달라고 하면서 완벽한 수식을 만들어갈 수 있습니다. 엑셀 도구 사용을 위해서는 엑셀 2016 이상이 설치되어 있어야 합니다.
이전에는 문제 없었던 것인데, 오랫만에 실행했더니 ‘import “pandas” could not be resolved from source’ 에러가 나오고, pandas와 numpy 아래에 노란색 물결이 그려져 있습니다. 이럴 경우 해결 방법을 알아보려고 합니다. 이미 문제가 있으므로 “Ⅰ. 원인 찾기”는 하지 않아도 됩니다.
(import “pandas” 에러 화면)
(pandas와 numpy 아래 노란색 물결 표시)
Ⅰ. 원인 찾기
1. 현재 실행되는 Python 확인
가. 첫번째 방법
where python # 윈도우
출력 예시 :
나. 두번째 방법
python -c "import sys; print(sys.executable)"
을 입력하면 실제 실행되는 Python 경로가 나옵니다.
출력 예시 :
2. pip이 설치한 Python 확인
pip -V
출력 예시 :
여기서 (python 3.12)이 실제 설치된 Python 버전입니다.
3. 경로가 같은지 비교
sys.executable로 확인한 경로와
pip -V의 마지막에 나온 Python 경로
👉 이 둘이 같아야 하는데, 위와 같이 실행 파일의 버전은 3.13인데, pip이 설치한 버전은 3.12으로 다릅니다.