안녕하세요. 궁금한게 있어 글 남깁니다. Model과 View에는 struct를 사용해주셨고 ViewModel에는 class를 사용해주셨는데 이렇게 사용하는 것이 일반적이라고 생각하면 좋을까요? 강의를 보고 궁금하여 좀 찾아보니 참조 타입이나 값 타입에 대해 좀 알게 되었는데 크게 와닿지 않아서 일단은 외우고 진행해야하나 싶더라구요
현재 지원되는 selenium 4.x 버전에서는, driver.find_element_by_id() 메서드가 더 이상 지원되지 않습니다. 라이브러리에 from selenium.webdriver.common.b y import By 을 추가하시고 search = driver.find_element (By.I D, 'query') menu = driver.find_element(By.CSS_SELECTOR,'div.dp2 > ul >li:nth-child(1) > a') 이렇게 하셔야 현재 24.09 기준으로 selenium 설치하신 분들은 코드가 무리 없이 돌아가실 거에요. 크롬 드라이버 역시 버전 115 이후부터는 통합으로 운영되어 https://googlechromelabs.github.io/chrome-for-testing/ 여기 페이지로 들어가셔서 아래쪽 stable(안정화) 버전에서 본인에게 맞는 운영체계의 크롬드라이버의 url을 주소창에 넣으시면 크롬드라이버를 다운 받으실 수 있습니다. 크롬과 셀레니움의 경우 계속해서 버전이 자동적으로 업되는 경우가 많아, 바로 전에 되던 코드가 실행이 되지 않는 경우도 있으니 버전들을 잘 확인하셔야 해요.
동적 페이지 크롤링 하고 있는데.. 어떤 경우에는 select_one를 사용하 또 다른 경우에는 get_attribute이걸 쓰더라고요.. 어떤 때에 각각 쓰는건지 아직 이해를 못했어요. 뭔가 알것같기도 하고.. 또 사용도 할 수는 있을 것 같은 좀 더 정확하게 이해하고 싶어요. 예를 들면 (맞는 코드는 아니지만) # 제목 가져오기 from bs4 import BeautifulSoup html = driver.page_source soup = BeautifulSoup(html, 'html.parser') items = soup.select('#main-area > div:nth-child(4)') for item in items: title = item.select_one('.article').text.strip() link = item.select_one('.article').attrs['href'] print(title,link) 이런 식으로 쓰기도 하니까 좀 헷깔립니다. 단순히 정적페이지/동적페이지에 따라 맞게 쓰는걸까요?
안녕하세요? 바탕화면에 codecamp-frontend 라는 폴더를 만들고, 그 아래에 class 라는 폴더를 만들어서 리액트 첫 보일러플레이트를 만들었습니다. section01 폴더도 만들고, 차근차근 하고 있습니다. 그런데, 깃허브로 바탕화면에 있는 codecamp-frontend 라는 폴더를 관리해주고 싶은데, 배운 대로 git init 을 하고 git add . 을 하니, 터미널에서, 이 폴더의 하위에 있는 class 라는 폴더가 서브모듈이 된다고 경고가 뜹니다. 그래서 검색을 해서 어찌어찌 되돌리고, 하위에 있는 class 폴더만 깃허브 리포지토리로서 관리하게 되었습니다. 그런데 class라는 이름의 리포지토리가 있는 것이 마음에 안 들고, 몇 가지 질문이 생겼습니다. 리액트 앱은 그 자체를 단독으로, 하나의 리포지토리로서 관리해주는 것이 맞나요? class 라는 이름의 리포지토리가 있는 것이 알아보기 어렵고 중복이 쉬워 이름을 바꾸고 싶습니다. 바꿔주어도 상관없을까요? 깃이 꼬이지 않을까요? 깃과 깃허브로 리액트 앱들을 하나의 폴더(리포지토리(저장소))로 모아서 관리하려면 어떻게 관리해 주어야 하는 건지 궁금합니다. 감사합니다.
안녕하세요. 열심히 강의 수강하고 있는 학생입니다. 강의가 너무 알차고 설명도 잘 해주셔서 즐겁게 보며 배우고 있는데 제목과 같이 중급, 고급 강의 계획도 있으신지 궁금합니다. 하신다면 무조건 구매(?) 할 생각인데 계획이 없으셨다면 고민 한번 부탁드리며 좋은 강의 다시금 감사드립니다.
안녕하세요. 우선 강사님, 좋은 강의 잘 듣고 있습니다. [섹션 5. Template Variable > Airflow 날짜개념] 강의 관련하여 질문 드립니다. Airflow 2.10.0 버전 사용 중이며, 강의와 같이 테스트를 진행하였는데, data_interval_start이 이전 배치일이 아닌 배치일로 나와서 문의드립니다. DAG의 start_date를 2024년 9월 1일로 설정 후 소급 처리하였습니다. 아래와 같이 dag_run이 배치일일텐데, 왜 data_interval_start가 이전 배치일(2024.08.31)이 아닌 배치일로 나올까요? ' dag_run ': <DagRun dags_python_show_templates @ 2024-09-01 00:30:00 +00:00: scheduled__2024-09-01T00:30:00+00:00, state:running, queued_at: 2024-09-06 09:11:26.187022+00:00. externally triggered: False>, ' data_interval_end ': DateTime(2024, 9, 2, 0, 30, 0, tzinfo=Timezone('UTC')), ' data_interval_start ': DateTime(2024, 9, 1, 0, 30, 0, tzinfo=Timezone('UTC')), 'ds': '2024-09-01',
본문제목 그대로 워크 벤치 이용할 때, 항상 패스워드를 입력한 후 활성화 되는 것으로 알고 있었는데, 현재 패스워드 입력 안하고 그냥 클릭만 해도 활성화됩니다. 보안상으로 좋지 않은 것 같은데, 혹시 이런 경우 어떻게 변경이 가능할까요? 오랜만에 mysql을 공부하는데 몇년 전에는 항상 패스워드 입력했던 것 같은데 이번에 새로 깔아보니 패스워드 입력 안해도 실행이 되어 불안합니다. 참고로 저는 맥 환경에서 사용하고 있습니다.
[리뉴얼] 처음하는 MongoDB(몽고DB) 와 NoSQL(빅데이터) 데이터베이스 부트캠프 [입문부터 활용까지] (업데이트)
MongoDB Aggregateion 기본 명령 이해하기1 수업 3분쯤에 db.movies.aggregate([{$match:{year:1995}]) 문법을 그대로 따라 쳤는데, 에러같은건 전혀 나지 않고 이 화면이 나옵니다. movies콜렉션에 데이터가 아무것도 안들어있는건가요?? 뭐가 문제인건지 모르겠습니다 ㅠㅠ 이것저것 찾아보니 제가 설치한 movies 컬렉션에는 데이터가 0건인거 같은데 왜 이런건가요? 강의에서 하라는대로 그대로 따라했습니다 ㅠ 몇 번 삭제하고 다시 해봐도 똑같이 데이터가 0건인거같아요
안녕하세요 강의를 듣고 next-auth를 활용하여 개발 중에 궁금한 점이 생겨 질문 드립니다. 프로젝트에서 일반 로그인과 소셜 로그인을 모두 사용하고 있어 next-auth의 signin callback에서 로그인일 경우 자체 서버에 요청하여 accessToken과 refreshToken을 발급 받고 jwt callback에서 엑세스 토큰의 만료 시간을 체크하여 만료 시에 재발급 요청이 되도록 구현하고 있습니다. 이렇게 구현했을 경우 간헐적으로 서버 시간과의 타이밍 이슈 때문인지 api 요청 시에 401 토큰 만료 에러가 발생하는 순간이 존재합니다. 따라서 401 상태코드일 경우에 refreshToken 토큰 재발급 요청을 하려고 하는데 refreshToken이 현재 next-auth에서 jwt 콜백에서 리턴되어 jwt토큰으로 생성되어 있습니다. 이 401일 경우 재발급 요청 처리를 클라이언트 단에서 할 경우 refreshToken이 노출되어 보안상 이슈가 있을 것으로 예상이 되는데 서버단에서 처리를 하려면 next에서 어디서 처리를 하면 좋을 지 문의드립니다. async signIn({ account, user, credentials }) { const cookieStore = cookies(); const authorizationParams = JSON.parse( cookieStore.get("authorization-params")?.value ?? "" ); const action = authorizationParams.action; user.platform = authorizationParams.platform; if (!account?.provider || !sns_type_map[account.provider]) { throw new Error("Unsupported provider"); } user.snsType = sns_type_map[account.provider]; if (action === auth_action_type.signin) { return handleSignIn(user); // getAccessToken } if (action === auth_action_type.signup) { return handleSignUp(); } return false; }, async jwt({ token, account, user }) { // Initial sign in if (account && user) { return { ...token, ...user, accessToken: user.refreshToken, expiresAt: new Date( Date.now() + (user?.expiresIn ?? 0) ).toISOString(), refreshToken: "refreshtoken", }; } // Return previous token if the access token has not expired yet if (new Date() < new Date(token.expiresAt as string)) { console.log("@@@@@@valid"); return token; } else { // Access token has expired, try to update it console.log("@@@@@@expired"); const cookieStore = cookies(); const authorizationParams = JSON.parse( cookieStore.get("authorization-params")?.value ?? "" ); const body = { .... }; const tokenData = await authApi.reissueAccessToken(body); // reissue token return { ...token, ...user, accessToken: tokenData.accessToken, expiresAt: new Date( Date.now() + (tokenData.expiresIn ?? 0) ).toISOString(), refreshToken: tokenData.refreshToken, }; } }, 미들웨어에서 401 상태 코드 처리하는 것도 알아보았으나 일반적인 방식인지 궁금합니다. 미들웨어에서 401일때 재발급 요청 시 새로운 엑세스 토큰으로 재요청이 정상적으로 되는 것은 확인했으나 다시 next-auth의 jwt토큰에 재발급된 값을 세팅해줘야 하는데 어떻게 해야할지도 궁금합니다. import { NextResponse } from 'next/server'; import { getToken } from 'next-auth/jwt'; export async function middleware(request) { const token = await getToken({ req: request, secret: process.env.AUTH_SECRET }); if (request.nextUrl.pathname.startsWith('/gateway')) { const accessToken = token?.accessToken; const headers = new Headers(request.headers); if (response.status === 401) { const refreshToken = token?.refreshToken; const refreshResponse = await fetch("/reissueToken") const refreshData = await refreshResponse.json(); if (refreshResponse.ok) { const newAccessToken = refreshData.accessToken; headers.set('Authorization', `Bearer ${newAccessToken}`); const newResponse = NextResponse.next({ request: { headers: request.headers, }, }); } // 토큰 재발급 실패 시 처리 return NextResponse.redirect('/login'); } return NextResponse.next(response); } return NextResponse.next(); }
25분4초 영상 질문입니다. 1번에서 int*a가 미리 선언되었기 때문에 스왑이 정상작동 하는것일까요? 2번답 nx라는건 이상하게 보자말자 감이 오던데요..! 혹시 sizeof(a)-1 를 했다면 답으로 되었을까요..? 궁금하네요 29분 12초 상속문제 입니다. 이상하게 상속문제만 보면 손댈 엄두가 안나네요.. 시작만 하면 풀리는데 그 시작이 안됩니다 ㅠㅠ... Venicle obj = new Car("Spark")에서 new Car가 클래스 이름을 지칭하기 때문에 같은 클래스 이름을 찾아보면 되는걸까요?
import SwiftUI struct ContentView: View { @State private var ToggleCheck: Bool = false // @State 없으면 에러 왜? / 연산자 토글을 누른 후의 숫자 입력인지 체크하기 위한 변수 @State private var isAdditionActive = false // 덧셈 토글 체크 @State private var isSubtractionActive = false // 뺄셈 토글 체크 @State private var isMultiplicationActive = false // 곱셈 토글 체크 @State private var isDivisionActive = false // 나눗셈 토글 체크 @State private var printNumber: String = "0" // 계산식에 사용 or 화면에 출력한 내용을 담은 변수 @State private var totalNumber: Int = 0 // 토탈 계산 값 @State private var op: Character = " " @State private var buttonData: [[String]] = [ // 키패드 모음 2차원 배열 ["AC", "+/-", "%", "÷"], ["7", "8", "9", "X"], ["4", "5", "6", "-"], ["1", "2", "3", "+"], ["0", ".", "="]] var body: some View { ZStack{ Color.black.ignoresSafeArea() // 화면 전체 여백 없이 배경색 지정 VStack { Spacer() HStack{ Spacer() Text("\(Int(printNumber)!)") // 계산기의 숫자 출력 .padding() .font(.system(size: 73)) .foregroundColor(.white) } ButtonPosition() // C, +/-, %를 제외한 버튼을 화면에 추가 } } } func Reset(){ printNumber = "0" // 출력된 계산 숫자 UI 초기화 totalNumber = 0 // 연산의 토탈값을 담고 있는 변수도 당연히 초기화 ToggleCheck = false op = " " buttonData[0][0] = "AC" isAllfalse() // 버튼의 토글값 및 연산자 버튼 토글 UI도 모두 초기화 } func isAllfalse(){ // 연산자의 토글 버튼을 전부 해제 하기 위한 함수 isAdditionActive = false isSubtractionActive = false isMultiplicationActive = false isDivisionActive = false } func opIfSwitch(){ // 실질적인 계산을 위한 switch문 if op == " "{ totalNumber = Int(printNumber)! } else{ switch op{ case "÷": totalNumber /= Int(printNumber)! if printNumber == "0"{ // 비정상 종료.. 왜? printNumber = "오류" } case "X": totalNumber *= Int(printNumber)! case "-": totalNumber -= Int(printNumber)! case "+": totalNumber += Int(printNumber)! default: break } } printNumber = String(totalNumber) } // 내 코드의 계산 방식 작성할 것 이따가 func Division(){ // 나눗셈 opIfSwitch() } func Multiplication(){ // 곱셈 opIfSwitch() } func Minus(){ // 뺄셈 opIfSwitch() } func Plus(){ // 덧셈 opIfSwitch() } func Equal(){ // 등호 opIfSwitch() isAllfalse() ToggleCheck = false // =을 누른 후 결과 값에 추가로 연산을 진행할 때 이 코드 없으면 정상적으로 진행되지 않음 } func ButtonPosition() -> some View{ // 버튼 디자인 및 포지셔닝 함수 ForEach(buttonData, id: \.self){ line in HStack{ ForEach(line, id: \.self){ row in switch row{ case "AC", "C", "+/-", "%": ButtonDesign(row, .gray, .black) case "÷", "X", "-", "+", "=": ButtonDesign(row, .orange, .white) default: ButtonDesign(row, .init("NumberButton"), .white) } } } } } func ButtonDesign(_ value: String, _ backcolor: Color, _ fcolor: Color) -> some View{ // 공통 버튼 디자인 Button { switch value { case "÷": isDivisionActive = true // 나눗셈 버튼 토글 isAdditionActive = false isSubtractionActive = false isMultiplicationActive = false case "X": isMultiplicationActive = true // 곱셈 버튼 토글 isDivisionActive = false isAdditionActive = false isSubtractionActive = false case "-": isSubtractionActive = true // 뺄셈 버튼 토글 isAdditionActive = false isMultiplicationActive = false isDivisionActive = false case "+": isAdditionActive = true // 덧셈 버튼 토글 isSubtractionActive = false isMultiplicationActive = false isDivisionActive = false default: break } ButtonAction(value) } label: { Text(value) .frame(width: value == "0" ? 160 : 80, height: 80, alignment: value == "0" ? .leading : .center) .background((value == "÷" && isDivisionActive) || (value == "X" && isMultiplicationActive) || (value == "-" && isSubtractionActive) || (value == "+" && isAdditionActive) ? Color.white : backcolor) //.background(value == "÷" && isDivisionActive ? Color.white : backcolor) //.background(value == "X" && isMultiplicationActive ? Color.white : backcolor) .foregroundColor(value == "÷" && isDivisionActive || (value == "X" && isMultiplicationActive) || (value == "-" && isSubtractionActive) || (value == "+" && isAdditionActive) ? Color.orange : fcolor) .font(.system(size: 33)) .cornerRadius(40) } } func ButtonAction(_ value: String){ switch value { // 버튼을 누르면 case "AC", "C": // C를 누르면 Reset() // 초기화 버튼을 누르면 각종 상수 및 변수들이 초기화 됨 case "÷": // 나누기를 누르면 Division() // 실질적인 계산을 하는 함수 op = "÷" ToggleCheck = false case "X": // 곱하기를 누르면 Multiplication() // 실질적인 계산을 하는 함수 op = "X" ToggleCheck = false case "-": // 빼기를 누르면 Minus() // 실질적인 계산을 하는 함수 op = "-" ToggleCheck = false case "+": // 더하기를 누르면 Plus() // 실질적인 계산을 하는 함수 op = "+" ToggleCheck = false case "+/-": printNumber = String(Int(printNumber)! * -1) case "=": Equal() // 최종 결과를 출력하기 위한 스위치문 호출 op = " " // 내가 원하는 기능을 구현하기 위해 꼭 필요한 코드 printNumber = String(totalNumber) // 연산의 결과 값을 출력 totalNumber = Int(printNumber)! default: if printNumber == "0"{ printNumber = value // 숫자 첫 입력시 화면에 출력 buttonData[0][0] = "C" } else if (isDivisionActive || isMultiplicationActive || isSubtractionActive || isAdditionActive) && ToggleCheck == false{ printNumber = value ToggleCheck = true // 연산자 버튼이 눌러짐 } else{ if printNumber.count < 9{ printNumber += value } } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } 안녕하세요! 다름이 아니라 강의에 있는 프로젝트 외에 따로 계산기를 하나 만들어보고 있습니다 근데 @State 어노테이션에 대해 이해가 안되는 부분이 있습니다 구글링도 해보고 여러 방면으로 알아봤는데 원하는 답을 얻지 못해서 질문 올립니다 @State는 뷰의 상태 변화를 체크하는 어노테이션이라고 알고 있습니다. 변수 선언부의 주석을 보시면 @State 없으면 에러 왜? 이런 내용의 주석이 달려 있는 변수가 지금 저의 의문점입니다 ToggleCheck 변수와 totalNumber 변수는 뷰의 상태 변경에 직접적인 영향을 미치지 않기 때문에 @State가 필요 없다고 생각합니다. 근데 저 두 변수에 @State를 지우면 에러가 발생합니다. 일단 뷰의 변화는 실질적으로 totalNumber 변수의 값을 대입 받는 printNumber 변수이니 printNumber 변수에만 @State가 필요하다고 생각하는데 왜 에러가 발생하는 걸까요 마찬가지로 ToggleCheck 변수도 마찬가지로 체크용으로 사용하고 저 값이 변한다고 해서 직접적으로 뷰에 미치는 영향이 없는데 왜 @State가 필요한 걸까요... 혹시 알고 계시면 꼭 답변 부탁드리겠습니다...! 감사합니다!
조건반복문 강의 4분 40초쯤에서 if절 에서 2의약수 또는 3의약수가 참일때, 6의 배수가 아닌것을 세어라. 로 해석되는데요. 1.일단 해당강의에서 ‘약수’로 표현한건 전부 ‘배수’인거죠? 모두 %정수로 표기되는데 약수, 배수 혼용되어서요. ll 연산자는 둘중 하나만 참이어도 전체가 참...으로 배웠는데! 왜 각각의 배수를 함께합쳐서 12개로 풀어야하는지 이해가 안갑니다. 11:51초에서도 &&연산자는 둘다 참이어야 참인데, 위와 마찬가지로 2의배수중 3의배수가 아닌것을 골라야하는대 왜 이렇게 적용되는지 이해가 안갑니다. if문이 계속 괄호안에 반복되면 순차적으로 조건문을 실행하여 참인지 보면 되는건가요? 혹시 강좌에 나오는 예제들만 모아놓은 출력물은 없을까요? 강좌에서 나오는 꼭외워야할부분, 강의 마지막에 나오는 요약문도 출력물이 없을까요? 예제문제를 다시풀어보고싶은데 강의마다 예제나오는 부분을 찾아보기가 시스템이 수월하지않아서요 .
import requests from bs4 import BeautifulSoup keyword = input("검색할 상품을 입력하세요 : ") url = f"https://search.shopping.naver.com/search/all?&query={keyword}" user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" headers = {"User-Agent" : user_agent} req = requests.get(url, headers=headers) html = req.text soup = BeautifulSoup(html, "html.parser") print(soup) 위 코드 사용 시 아래와 같은 결과가 나타납니다. keyword = input("검색할 상품을 입력하세요 : ") url = f"https://search.shopping.naver.com/search/all?&query={keyword}" user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" headers = {"User-Agent" : user_agent} req = requests.get(url, headers=headers) # req = requests.get(url, headers=headers) # print(req.request.headers) html = req.text soup = BeautifulSoup(html, "html.parser") print(soup) <title>네이버쇼핑</title> </head> <body> <div class="content_error"> <div class="head">쇼핑 서비스 접속이 일시적으로 제한되었습니다. </div> <div class="desc"> 네이버는 안정적인 쇼핑 서비스 제공하고자 시스템을 통해 아래와 같은 비정상적인 접근이 감지될 경우 해당 네트워크의 접속을 일시적으로 제한하고 있습니다. </div> <ul class="reason"> <li>상품 구매, 탐색과 무관한 외부 이벤트를 통한 접속</li> <li>짧은 시간 내에 너무 많은 요청이 이루어진 IP</li> <li>VPN을 사용하여 접속한 IP</li> <li>특정 확장 프로그램 이용 시</li> </ul> <div class="footer">위와 같은 접근이 아님에도 접속이 제한된 경우,네이버앱을 업데이트 또는 <a href="https://help.naver.com/service/30016/category/5278" target="_blank"> 원클릭 진단</a>을 부탁드립니다.<br/> 해당 방법을 통해서도 접속이 불가한 경우 <a href="https://help.pay.naver.com/mail/form.help?alias=shopping_stop" target="_blank">네 이버쇼핑 고객센터</a>로 문의 부탁드립니다.</div> </div> </body> </html> 이런 상황에서 대안이 있을까요?