useEffect 함수는 리액트 컴포넌트가 랜더링 될 때마다 특정 작업을 실행할 수 있도록 하는 Hook

 

component가 mount 됐을 때, unmount 됐을 때 update 됐을 때 특정 작업을 처리할 수 있다.

 

기본형태

useEffect(function, deps)

- function : 수행하고자 하는 작업

- deps : 배열 형태이며, 배열 안에는 검사하고자 하는 특정 값 or 빈 배열

 

useEffect();

useEffect(()=>{
    console.log('마운트 될 때만 실행');
}, []);
useEffect(()=>{
    console.log('랜더링 될 때 마다 실행');
});
useEffect(()=>{
    console.log('업데이트 될 때 실행');
}, [name]);

 

 

Express.js를 사용하여 서버를 구축할 때 자주 사용되는 여러 라이브러리가 있습니다. 여기에서 언급하신 `axios`, `body-parser`, `nodemon`, `cors` 각각에 대해 간단히 설명드리겠습니다:

 

0. Express

 - xpress.js는 Node.js를 위한 가장 인기 있는 웹 프레임워크 중 하나로, 웹 애플리케이션과 API를 빠르고 쉽게 구축할 수 있도록 설계되었습니다. 이 프레임워크는 간결하고 유연한 구조를 제공하여, 개발자가 필요에 따라 기능을 확장할 수 있게 해줍니다. Express.js는 Node.js의 'http' 모듈 위에 구축되어, 향상된 웹 서버 기능을 제공합니다.


1. **Axios**:
   - Axios는 Promise 기반의 HTTP 클라이언트 라이브러리로, 브라우저와 Node.js 환경에서 사용할 수 있습니다. 서버에서 다른 서버로 요청을 보내거나, REST API를 호출할 때 매우 유용합니다. Axios는 자동으로 JSON 데이터를 변환하고, HTTP 요청을 쉽게 만들 수 있는 API를 제공합니다.

2. **Body-parser**:
   - Body-parser는 Express 애플리케이션에 들어오는 요청의 본문(body)을 파싱하는 미들웨어입니다. 클라이언트에서 서버로 데이터가 전송될 때, 이 데이터를 적절히 추출해서 req.body 객체로 만들어주는 역할을 합니다. JSON 데이터 뿐만 아니라 URL 인코드 데이터도 처리할 수 있습니다. 최근의 Express 버전(4.16.0 이상)에서는 body-parser의 기능이 Express에 내장되어 별도로 설치할 필요가 없어졌습니다.

3. **Nodemon**:
   - Nodemon은 Node.js 기반의 애플리케이션을 개발할 때 매우 유용한 도구입니다. 소스 코드에 변경이 발생하면 자동으로 Node 애플리케이션을 재시작해줍니다. 이를 통해 개발 과정에서 매번 서버를 수동으로 재시작하지 않아도 되어 개발 효율성을 높여줍니다.

4. **CORS (Cross-Origin Resource Sharing)**:
   - CORS는 웹 페이지가 다른 도메인의 자원을 요청할 수 있게 해주는 보안 기능입니다. 예를 들어, 도메인 A의 웹 페이지가 도메인 B의 API를 호출할 때 CORS 정책에 의해 허용된 요청만 수행할 수 있습니다. Express에서는 `cors` 미들웨어를 사용하여 쉽게 CORS 정책을 설정할 수 있습니다. 이를 통해 다른 도메인에서의 요청을 안전하게 허용하거나 제한할 수 있습니다.

이 라이브러리들은 각각의 역할이 있으며, Express.js와 함께 사용함으로써 웹 서버 개발을 더욱 효율적이고 강력하게 할 수 있습니다.

server.js

// 설치한 라이브러리를 가져온다
const express = require('express');
const app = express();      // 기본적으로 express를 사용할 수 있는 변수를 생성

// express포트 설정
const PORT = process.env.PORT || 5000;


const bodyParser = require('body-parser');
const cors = require('cors');

// config body-parser
app.use(bodyParser.json());
app.use(cors());

// mysql 데이터베이스 사용
const mysql = require('mysql');

// db 접속 정보 
const db = mysql.createConnection({
    host: "127.0.0.1",
    user: "user_icia",
    password: "1111",
    port: "3306",
    database: "db_icia"
});

//db접속
db.connect((err)=>{
    if(!err){
        console.log('db접속 성공!');
    } else {
        console.log('db접속 실패!');
    }
});

// 서버 접속
app.listen(PORT, () => {
    console.log(`Server On : http://localhost:${PORT}`);
});

// 처음 express에 접속 했을 경우
app.get('/', (req, res) => {
    console.log('root!');
});


// 게시글 목록 불러오기
app.get('/list', (req, res) => {
    console.log(`app.get('/list')`);
    
    const sql = "select * from board order by id desc";
    db.query(sql, (err, data) => {
        if(!err){
            // console.log(data);
            res.send(data);
        } else {
            console.log(err);
        }
    });
});

// 게시글 상세보기
app.get('/view/:id', (req, res) => {
    const id = req.params.id;
    console.log(`app.get('/view/${id}')`);


    const sql = "select * from board where id=?";
    db.query(sql, [id], function(err, data) {
        if(!err){
            console.log(data);
            res.send(data);
        } else {
            console.log(err);
        }
    });
});




//게시글 등록
app.post('/insert', function(req, res) {
    const title=req.body.title;
    const contents=req.body.contents;
    const writer=req.body.writer;

    console.log(title, contents, writer);

    const sql='insert into board(title, contents, writer) values(?,?,?)';

    db.query(sql, [title, contents, writer], function(err, data){
        if(!err){
            console.log(data);
            res.sendStatus(200);
        } else {
            console.log(err);
        }
        
    });
});

//게시글 수정
app.post("/update/:id", function(req, res) {
    console.log(`수정 확인!`);

    const id = req.params.id;
    const title=req.body.title;
    const contents=req.body.contents;
    const writer=req.body.writer;

    console.log(id, title, contents, writer);

    const sql='update board set title=?, contents=?, writer=? where id=?';

    db.query(sql, [title, contents, writer, id], function(err, data){
        if(!err){
            console.log(data);
            res.sendStatus(200);
        } else {
            console.log(err);
        }
    });
});

// 게시글 삭제
app.post('/delete/:id', (req, res) => {
    
});

 

App.js

import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import BoardMain from './component/BoardMain';

function App() {

  return (
    <div className="App">
      <BoardMain />
    </div>
  );
}

export default App;

BoardMain.jsx

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import BoardMain from './BoardMain';
import BoardWrite from './BoardWrite';
import BoardView from './BoardView';
import BoardList from './BoardList';
import BoardModify from './BoardModify';

const BoardMain = () => {

    return (
        <div id="board-main">
            <BrowserRouter>
                <Routes>
                    <Route path="/" element={<BoardList />} />
                    <Route path="/list" element={<BoardList />} />
                    <Route path="/write" element={<BoardWrite />} />
                    <Route path="/view/:id" element={<BoardView />} />
                    <Route path="/modify/:id" element={<BoardModify />} />
                </Routes>
            </BrowserRouter>
        </div>
    )
}

export default BoardMain;

BoardList.jsx

import { Table, Button} from 'react-bootstrap'
import { useEffect , useState } from 'react';
import axios from 'axios';
import {Link} from 'react-router-dom'

const BoardList = () => {

    const [boardList, setBoardList] = useState({});

    // hook의 일종
    // 마운트와 업데이트 사이
    // 컴포넌트가 랜더링 될 때 , 업데이트 될 때 실행
    
    const getBoardData = async () => {
        const boards = await axios('/list');
        console.log(boards);
        setBoardList(boards.data);
    }

    useEffect(() => {
        getBoardData()
    }, []); // 



    if(boardList.length>0){
        return(
            <div className='board-list'>
                <h1>게시글 목록</h1>

                <Table striped bordered hover>
                <thead>
                    <tr>
                        <th>번호</th>
                        <th>제목</th>
                        <th>작성자</th>
                        <th>작성일</th>
                    </tr>
                </thead>
                <tbody>
                        {boardList.map(boards=>(
                        <tr >
                            <td>{boards.id}</td>
                            <td><Link to={`/view/${boards.id}`}>{boards.title}</Link></td>
                            <td>{boards.writer}</td>
                            <td>{boards.reg_date}</td>
                        </tr>)
                        )}
                    </tbody>
                
            </Table>
            <Link to={`/write`} >
                    <Button className='mx-2 btnWrite'>작성하기</Button>
                </Link>
            </div>
                
           
        );
    }


}

export default BoardList;

BoardWrite.jsx

import axios from 'axios';
import React, { useState } from 'react'
import { Row, Col, Form, Button } from 'react-bootstrap'


const BoardWrite = () => {

    const [form, setForm] = useState({
        title: '',
        contents: '',
        writer: ''
    });

    const { title, contents, writer } = form;

    const onChange = (e) => {
        setForm({
            ...form, 
            [e.target.name] : e.target.value
        })
    }

    const onSubmit = async () => {
        if (title === '') {
            alert('제목을 입력하세요!');
        } else if (contents === '') {
            alert('내용을 입력하세요!');
        } else {
            if (window.confirm('게시글을 등록하시겠습니까?')) {
                await axios.post('/insert', form);
                window.location.href = "/list";
            }
        }
    }

    const onReset = () => {
        setForm({
            ...form,
            title: '',
            contents: '',
            writer: ''
        });
    }

    return (
        <Row className='my-5'>
            <Col className='p-5'>
                <h1 className='text-center my-5'>게시글 작성</h1>
                <Form>
                    <h4>제목</h4><Form.Control placeholder='제목을 입력하세요.'
                        className='my-3' name='title' value={title} onChange={onChange} />

                    <h4>작성자</h4><Form.Control placeholder='작성자를 입력하세요.'
                        className='my-3' name='writer' value={writer} onChange={onChange} />

                    <h4>내용</h4><Form.Control as='textarea' rows={10} placeholder='내용을 입력하세요.'
                        className='my-3' name='contents' value={contents} onChange={onChange} />

                    <div className='text-center'>
                        <Button className='mx-2 px-3 btn-sm' onClick={onSubmit}>저장</Button>
                        <Button className='mx-2 px-3 btn-sm' onClick={onReset} variant='secondary'>초기화</Button>
                    </div>
                </Form>
            </Col>
        </Row>
    )
}

export default BoardWrite;​

 

BoardView.jsx

import React, { useEffect, useState } from 'react';
import { useParams , Link  } from 'react-router-dom';
import axios from 'axios';
import {Row, Col, Button, Card} from 'react-bootstrap'


const BoardView = () => {

    const { id } = useParams(); // /board/:id와 동일한 변수명으로 데이터를 꺼낼 수 있습니다.
    const [board, setBoard] = useState({});

    const getBoard = async () => {
        const board = await axios.get(`/view/${id}`);
        console.log(`/view/${id}`);
        setBoard(board.data[0]);
    }

    useEffect(() => {
        getBoard();
    },[]);

    const onDelete = async() => {
        if(window.confirm(id + '번 게시글을 삭제하시겠습니까?')) {
            
        }
    }

    return (
        
        <div className="board-view">
            <Row className='my-5'>
            <Col className='px-5'>
                <h1 className='my-5 text-center'>{board.id}번 게시글 정보</h1>
                <div className='text-end my-2'>
                    <Link to={`/modify/${id}`}>
                        <Button className='btn-sm mx-2'>수정</Button>
                    </Link>
                    <Button className='btn-sm' variant='danger'
                        onClick={onDelete}>삭제</Button>
                </div>
                <Card>
                    <Card.Body>
                        <h5>[{board.id}] {board.title}</h5>
                        <hr/>
                        <div className='cArea'>{board.contents}</div>
                    </Card.Body>
                    <Card.Footer>
                        Created on {board.reg_date} by {board.writer}
                    </Card.Footer>
                </Card>
            </Col>
        </Row>
        </div>
    );
};

export default BoardView;

BoardModify.jsx

import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import { Row, Col, Form, Button } from 'react-bootstrap'


const BoardModify = () => {

    const { id } = useParams();

    const [board, setBoard] = useState({});
    const getBoard = async () => {
        const board = await (await axios.get(`/view/${id}`));
        setBoard(board.data[0]);
    };
    useEffect(() => {
        getBoard();
    },[]);
    
    
    const [form, setForm] = useState({
        title: '',
        contents: '',
        writer: ''
    });

    const { title, contents, writer } = form;

    const onChange = (e) => {
        setForm({
            ...form,
            [e.target.name]: e.target.value
        })
    }

    const onReset = () => {
        setForm({
            ...form,
            title: '',
            contents: '',
            writer: ''
        });
    }

    const onSubmit = async () => {
        if (title === '') {
            alert('제목을 입력하세요!');
        } else if (contents === '') {
            alert('내용을 입력하세요!');
        } else {
            if (window.confirm('게시글을 수정하시겠습니까?')) {
                await axios.post(`/update/${id}`, form);
                window.location.href = "/list";
            }
        }
    }

    

    return (
        <Row className='my-5'>
            <Col className='p-5'>
                <h1 className='text-center my-5'>게시글 수정</h1>
                <Form>
                    <h4>제목</h4> <Form.Control placeholder={board.title}
                        className='my-3' name='title' value={title} onChange={onChange} />

                    <h4>작성자</h4><Form.Control placeholder={board.writer}
                        className='my-3' name='writer' value={writer} onChange={onChange} />

                    <h4>내용</h4><Form.Control as='textarea' rows={10} placeholder={board.contents}
                        className='my-3' name='contents' value={contents} onChange={onChange} />
                    <div className='text-center'>
                        <Button className='mx-2 px-3 btn-sm'
                            onClick={onSubmit}>저장</Button>
                        <Button className='mx-2 px-3 btn-sm'
                            onClick={onReset} variant='secondary'>초기화</Button>
                    </div>
                </Form>
            </Col>
        </Row>
    );
};

export default BoardModify;​

 

package.json

{
  "name": "board-test",
  "version": "0.1.0",
  "private": true,
  "proxy": "http://localhost:5000/",
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",

    "axios": "^1.5.1",
    "body-parser": "^1.20.2",
    "bootstrap": "^5.3.2",
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "json": "^11.0.0",
    "mysql": "^2.18.1",
    "nodemon": "^3.0.1",
    "react": "^18.2.0",
    "react-bootstrap": "^2.9.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.16.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

[0] 개발환경
 - nodejs 설치
 - VSCode 설치

[1] React 프로젝트 생성
 - npx create-react-app 'react-basic'

 - 안될 경우 
 - npm uninstall -g create-react-app
 - npm install -g create-react-app
 - npx create-react-app 'react-basic'

[2] 프로젝트 실행
 - npm start
 - localhost:3000
 - public/index.html의 (id="root")는
 - src/index.js의 document.getElementById('root')에 렌더링 한다. 
 - src/index.js의 <App />은 
 - src/App.js의 function App(){} (App 컴포넌트)의 return안에 있는 내용을 가져와서 출력한다.

[3] 프로젝트 구성 설명
 - node_modules : 라이브러리 폴더
 - public폴더
   └ index.html이 메인페이지 (App.js → index.js → index.html)
   └ static파일 보관함
 - src폴더 : 소스코드 보관함
 - package.json : 설치한 라이브러리 목록

[4] 컴포넌트 설명
 - 리액트(React) 컴포넌트는 React 애플리케이션을 구성하는 기본 단위(UI의 한부분)
 - 독립적이고 재사용 가능한 코드 블록
 - 자체적인 구조, 스타일, 동작
 - 큰 UI를 관리하기 쉬운 작은 단위로 분할하여, 애플리케이션의 코드를 더 효율적으로 관리하고 재사용

 - 클래스형과 함수형 컴포넌트가 있지만 최근에는 함수형을 사용한다.
 - 함수형 컴포넌트 snippet : "rsc" 자동완성

[5] 컴포넌트 활용 알아보기
  (1) App.js

import './App.css';
import Strat from './component/Start';


function App() {

  return (
    <div className="App">
      <Strat />
    </div>
  );
}

export default App;


  (2) Start.jsx

import React from 'react';

const Start = () => {

    // 해당 영역에서는 이와 같이 주석을 사용할 수 있습니다.
    const name = "도깨비";

    // JSX(JavaScriptXML) : 코드 간결, 가독성 좋음
    // JSX를 사용하는 주요 이유 중 하나는 JavaScript 함수 내에서 HTML과 유사한 문법을 사용할 수 있게 함으로써, 
    // 사용자 인터페이스(UI)를 더 직관적이고 선언적으로 구성

    const style = {
        color : "white",
        backgroundColor : "black",
        fontSize : "48px",
        fontWeight : "bold",
        padding : "16px"
    }

    return (
        <div className='start'>
            <h2>이 곳은 Start.jsx 영역입니다.</h2>
            <h2>Start.jsx 내용이 출력됩니다.</h2>

            {/* 주석은 아래와 같이 작성합니다. */}
            {/* {React.createElement('h2', null, `${name}님 반갑습니다.`)} */}
            <h2 style={style}>{name}님 반갑습니다.</h2>
        </div>
    );
};

export default Start;

 

[6] 리액트 레이아웃 + css 적용하기

import './App.css';
import Header from './component/Header';
import Home from './component/Home';
import Footer from './component/Footer';

function App() {

  return (
    <div className="App">
      <Header/>
      <Home/>
      <Footer/>
    </div>
  );
}

export default App;

 

import React from 'react';

const Header = () => {
    return (
        <div className='header'>
            Header.jsx
        </div>
    );
};

export default Header;
import React from 'react';

const Home = () => {
    return (
        <div className='home'>
            Home.jsx
        </div>
    );
};

export default Home;
import React from 'react';

const Header = () => {
    return (
        <div className='header'>
            Header.jsx
        </div>
    );
};

export default Header;
import React from 'react';

const Footer = () => {
    return (
        <div className='footer'>
            <h3>COPYRIGHT © 2024 BY ICIA ALL RIGHTS RESERVED.</h3>
            <h2>프로젝트 기반의 리액트 기초 보수교육</h2>
            <h4>한국기술교육대학교 능력개발교육원 & 인천일보아카데미</h4>
        </div>
    );
};

export default Footer;
* {
    margin: 0;
    text-align: center;
}

.header {
    background-color: lightpink;
    height: 100px;
}

.home {
    background-color: lightblue;
    height: 400px;
}

.footer {
    background-color: lightgreen;
    height: 150px;
}

'Python' 카테고리의 다른 글

[Python] konlpy 형태소 분석  (0) 2024.03.22
[Python] 판다스 Pandas  (1) 2024.03.21
[Python] 유튜브 크롤링(2)  (0) 2024.03.20
[Python] 유튜브 크롤링(1)  (0) 2024.03.19
[Python] Selenium 소개 및 사용법  (0) 2024.03.18

'Python' 카테고리의 다른 글

오늘의 블로그  (0) 2024.04.03
[Python] 판다스 Pandas  (1) 2024.03.21
[Python] 유튜브 크롤링(2)  (0) 2024.03.20
[Python] 유튜브 크롤링(1)  (0) 2024.03.19
[Python] Selenium 소개 및 사용법  (0) 2024.03.18

ch21 판다스 라이브러리 소개 및 활용

<aside> 💡 이번 차시의 학습목표

✔ 판다스 기본 기능 이해

✔ 시리즈, 데이터프레임 기초 문법 이해

</aside>

01. pandas란

  1. 데이터 조작 및 분석을 위한 라이브러리
  2. 데이터과학의 많은 부분을 처리할 수 있으며 최적화된 도구
  3. 쉼표로 구분된 값, JSON, Excel과 같은 다양한 파일 형식에서 데이터를 가져올 수 있음
  4. 데이터를 표 형태로 다룰 수 있으며, pandas에서 제공하는 데이터의 종류는 다음과 같음
    1. 시리즈(Series)
      1. 1차원 배열과 같은 자료 구조
      2. 파이썬의 리스트 자료형과 비슷하지만 인덱스 값을 직접 지정할 수 있는 특징이 있음
      3. Series끼리의 연산시 인덱스를 기준으로 연산도 가능
    2. 데이터 프레임(DataFrame)
      1. 행(row), 열(column)로 이루어진 2차원 데이터 구조를 다룸
      2. 엑셀 또는 데이터베이스의 표(table)와 유사한 구조
      3. 각 열 데이터는 Series이며, DataFrame은 Series의 집합
      4. DataFrame 구조(공식홈페이지)
  5. 공식 홈페이지
    1. 🌐 https://pandas.pydata.org/
  6. 이름 유래
    1. PANel DAta라는 경제학 용어에서 가져온 말이며, 동물 팬더와는 관련 없음

02. pandas 설치 및 사용 방법

  1. pip install을 이용하여 모듈을 설치하고 사용해야 함. 사용시에는 일반적으로 pd로 줄여서 사용함.
    # 설치
    >> pip install pandas
    
    # 사용
    import pandas as pd

03. pandas 다뤄보기

  1. 시리즈(Series)
    1. 국어, 영어, 수학 성적을 다루는 시리즈
    2. 국어성적 시리즈 선언
      1. 시리즈 선언 시 pd.Series() 사용
        1. Series(담을데이터, 인덱스 값(생략시 0부터 순차값 생성))
          score_korean = pd.Series([98, 76, 60, 85, 80])
          print(score_korean)
    3. 인덱스 지정하여 시리즈 선언하기
      1. 인덱스 값을 1~5까지의 학번 데이터로 지정
        score_korean = pd.Series([98, 76, 60, 85, 80], index=[1, 2, 3, 4, 5])
        print(score_korean)
      2. range 함수 적용
        score_korean = pd.Series([98, 76, 60, 85, 80], index=range(1,6))
        print(score_korean)
    4. 학번 데이터를 따로 선언하여 영어, 수학 점수에도 활용
      student_number = [1, 2, 3, 4, 5]
    5. 성적 데이터도 따로 리스트로 선언하여 적용 가능
      korean_list = [98, 76, 60, 85, 80]
      score_korean = pd.Series([98, 76, 60, 85, 80], index=student_number)
    6. 영어 성적 시리즈 선언
      english_list = [88, 92, 100, 55, 70]
      score_english = pd.Series(english_list, index=student_number)
    7. 국어, 영어 성적 합계
      1. 시리즈 간의 연산도 가능하며 인덱스끼리 값을 계산함
        total = score_korean + score_english
    8. 수학 성적 시리즈 선언
      1. 학번은 1~5번 이지만 순서가 다른 경우
        score_math = pd.Series([30, 20, 10, 40, 50], index=[3, 2, 1, 4, 5])
      2. 인덱스 순으로 정렬하여 출력할 때는 sort_values()를 사용하며, 매개값으로 정렬 기준을 넘김
        print(score_math.sort_index())
    9. 전체 성적 합계
      1. 수학 성적 시리즈를 만들 때 인덱스 순서는 달랐지만 계산시에는 인덱스끼리 계산을 하기 때문에 학번별로 성적 합산이 됨
        total = score_korean + score_english + score_math
      2. 인덱스, 값 기준으로 정렬하여 출력하기
        # 인덱스 기준 오름차순 정렬
        print(total.sort_index())
        # 인덱스 기준 내림차순 정렬
        print(total.sort_index(ascending=False))
        # 값 기준 오름차순 정렬
        print(total.sort_values())
        # 값 기준 내림차수 정렬
        print(total.sort_values(ascending=False))

 

03-1. 실습 예제

📥실습 코드

ex01_pandas_01.py

import pandas as pd

# Series 생성 
# 국어성적 정보
score_korean = pd.Series([98, 76, 60, 85, 80])
print(score_korean)

# 인덱스를 지정하여 Series 생성
score_korean = pd.Series([98, 76, 60, 85, 80], index=[1, 2, 3, 4, 5])
print(score_korean)

# range 함수 활용
score_korean = pd.Series([98, 76, 60, 85, 80], index=range(1,6))
print(score_korean)

# index 값 따로 선언 후 활용
student_number = [1, 2, 3, 4, 5]
score_korean = pd.Series([98, 76, 60, 85, 80], index=student_number)
print(score_korean)

# 성적 데이터도 리스트로 선언하여 활용 가능
korean_list = [98, 76, 60, 85, 80]
score_korean = pd.Series(korean_list, index=student_number)
print(score_korean)

# 영어 성적 추가 
english_list = [88, 92, 100, 55, 70]
score_english = pd.Series(english_list, index=student_number)
print(score_english)

# 국어, 영어 학생별 성적 합산 
total = score_korean + score_english
print(total)

# 수학 성적 추가(인덱스 번호가 1~5로 순차적이지 않음)
score_math = pd.Series([30, 20, 10, 40, 50], index=[3, 2, 1, 4, 5])
print(score_math)
print(score_math.sort_index())

# 전체 성적 합산(pandas가 인덱스 별로 계산을 수행함)
total = score_korean + score_english + score_math
print(total)

# 인덱스 기준 오름차순 정렬
print(total.sort_index())
# 인덱스 기준 내림차순 정렬
print(total.sort_index(ascending=False))
# 값 기준 오름차순 정렬
print(total.sort_values())
# 값 기준 내림차순 정렬
print(total.sort_values(ascending=False))

04. 데이터프레임 다뤄보기

  1. 데이터프레임은 아래와 같은 표 형태의 2차원 데이터를 다룰 수 있으며, 시리즈로 다뤄본 성적데이터를 코드로 구현학번 이름 국어 영어 수학
    1 김파이 96 88 10
    2 이파이 76 92 20
    3 박파이 60 100 30
    4 최파이 85 55 40
    5 정파이 80 70 50
  2. 데이터프레임 선언
    1. 데이터프레임 선언시 pd.DataFrame() 사용
    2. 문법
      pd.DataFrame(저장할데이터)
  3. 성적 데이터 입력해보기
    1. 과목별 점수를 리스트 단위로 입력 후 출력
      ex02_panda_series_01.py
      
      import pandas as pd
      
      scores = pd.DataFrame([
          [96, 76, 60, 85, 80], [88, 92, 100, 55, 70], [10, 20, 30, 40, 50]
      ])
      print(scores)
    2. 학생별 점수를 리스트 단위로 입력 후 출력
      ex02_panda_dataframe_01.py
      
      import pandas as pd
      
      scores = pd.DataFrame([
          [96, 88, 10], [76, 92, 20], [60, 100, 30], [85, 55, 40], [80, 70, 50]
      ])
      print(scores)
    3. 인덱스를 적용하여 데이터프레임 선언
      ex02_panda_dataframe_02.py
      
      import pandas as pd
      
      scores = pd.DataFrame([
          [96, 76, 60, 85, 80], [88, 92, 100, 55, 70], [10, 20, 30, 40, 50]
      ], index=["국어", "영어", "수학"])
      print(scores)
      
      scores = pd.DataFrame([
          [96, 88, 10], [76, 92, 20], [60, 100, 30], [85, 55, 40], [80, 70, 50]
      ], index=[1, 2, 3, 4, 5])
      print(scores)
    4. 컬럼명을 각각 지정하여 선언하기
      ex02_panda_dataframe_03.py
      
      import pandas as pd
      
      scores = pd.DataFrame(
          {
              "국어": [96, 76, 60, 85, 80],
              "영어": [88, 92, 100, 55, 70],
              "수학": [10, 20, 30, 40, 50]
          }, index=[1, 2, 3, 4, 5]
      )
      print(scores)
    5. 딕셔너리를 데이터프레임으로 변환해보기
      ex02_panda_dataframe_04.py
      
      import pandas as pd
      
      scores_dict = {"국어": [96, 76, 60, 85, 80],
                      "영어": [88, 92, 100, 55, 70],
                      "수학": [10, 20, 30, 40, 50]}
      
      scores = pd.DataFrame(scores_dict)
      print(scores)
      
      # 인덱스 지정
      scores = pd.DataFrame(scores_dict, index=[1, 2, 3, 4, 5])
      print(scores)
  4. 데이터프레임에 데이터 추가하기
    1. 이름 열 추가하기
      1. 문법
        데이터프레임이름[”추가할 열이름”] = 추가할데이터
      2. 데이터를 하나만 지정하는 경우
        scores["이름"] = "김파이"
      3. 데이터를 모두 지정하는 경우
        scores["이름"] = ["김파이", "이파이", "박파이", "최파이", "정파이"]
      4. 실습 코드
        ex02_panda_dataframe_05.py
        
        import pandas as pd
        
        scores = pd.DataFrame(
            {
                "국어": [96, 76, 60, 85, 80],
                "영어": [88, 92, 100, 55, 70],
                "수학": [10, 20, 30, 40, 50]
            }, index=[1, 2, 3, 4, 5]
        )
        print(scores)
        
        # 데이터 하나만 지정
        # scores["이름"] = "김파이"
        # 데이터 모두 지정
        scores["이름"] = ["김파이", "이파이", "박파이", "최파이", "정파이"]
        print(scores)
    2. 학생 행 추가하기
      1. 문법
        데이터프레임이름.loc['인덱스값'] = 추가할데이터
      2. 데이터를 하나만 지정하는 경우
        scores.loc[6] = 100
      3. 데이터를 모두 지정하는 경우
        scores.loc[6] = [100, 100, 100, "조파이"]
      4. 실습 코드
        ex02_panda_dataframe_06.py
        
        import pandas as pd
        
        scores = pd.DataFrame(
            {
                "국어": [96, 76, 60, 85, 80],
                "영어": [88, 92, 100, 55, 70],
                "수학": [10, 20, 30, 40, 50],
                "이름": ["김파이", "이파이", "박파이", "최파이", "정파이"]
            }, index=[1, 2, 3, 4, 5]
        )
        print(scores)
        
        # scores.loc[6] = 100
        scores.loc[6] = [100, 100, 100, "조파이"]
        print(scores)

 

05. 데이터 프레임 주요 method

  1. 성적 데이터프레임 준비

    scores = pd.DataFrame(
        {
            "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
            "국어": [96, 76, 60, 85, 80, 100],
            "영어": [88, 92, 100, 55, 70, 100],
            "수학": [10, 20, 30, 40, 50, 100],
        }, index=[1, 2, 3, 4, 5, 6]
    )
  2. transpose()
    1. 행, 열을 서로 맞바꿈
      ex03_pandas_method_01.py
      
      scores = pd.DataFrame(
          {
              "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
              "국어": [96, 76, 60, 85, 80, 100],
              "영어": [88, 92, 100, 55, 70, 100],
              "수학": [10, 20, 30, 40, 50, 100],
          }, index=[1, 2, 3, 4, 5, 6]
      )
      print(scores)
      scores = pd.DataFrame(
          {
              "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
              "국어": [96, 76, 60, 85, 80, 100],
              "영어": [88, 92, 100, 55, 70, 100],
              "수학": [10, 20, 30, 40, 50, 100],
          }, index=[1, 2, 3, 4, 5, 6]
      ).transpose()
      print(scores)
  3. sort_index()
    1. index 기준으로 정렬
    2. 매개변수로 내림차순, 오름차순을 지정할 수 있음(기본은 오름차순)
      ex03_pandas_method_02.py
      
      import pandas as pd
      
      scores = pd.DataFrame(
          {
              "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
              "국어": [96, 76, 60, 85, 80, 100],
              "영어": [88, 92, 100, 55, 70, 100],
              "수학": [10, 20, 30, 40, 50, 100],
          }, index=[1, 2, 3, 4, 5, 6]
      )
      print(scores.sort_index())
      # index 기준 오름차순 정렬
      print(scores.sort_index(ascending=True))
      # index 기준 내림차순 정렬
      print(scores.sort_index(ascending=False))
  4. sort_values()
    1. 값 기준으로 정렬
    2. 기준 열, 내림차순/오름차순에 대한 설정 가능
      ex03_pandas_method_03.py
      
      import pandas as pd
      
      scores = pd.DataFrame(
          {
              "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
              "국어": [96, 76, 60, 85, 80, 100],
              "영어": [88, 92, 100, 55, 70, 100],
              "수학": [10, 20, 30, 40, 50, 100],
          }, index=[1, 2, 3, 4, 5, 6]
      )
      print(scores)
      # 이름 기준 오름차순 정렬
      print(scores.sort_values(by="이름", ascending=True))
      # 이름 기준 내림차순 정렬
      print(scores.sort_values(by="이름", ascending=False))
      # 수학 기준 오름차순 정렬
      print(scores.sort_values(by="수학", ascending=True))
  5. head(), tail()
    1. 조회할 줄 수 지정하여 첫줄 또는 마지막줄 부터 숫자만큼 조회
      ex03_pandas_method_04.py
      
      import pandas as pd
      
      scores = pd.DataFrame(
          {
              "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
              "국어": [96, 76, 60, 85, 80, 100],
              "영어": [88, 92, 100, 55, 70, 100],
              "수학": [10, 20, 30, 40, 50, 100],
          }, index=[1, 2, 3, 4, 5, 6]
      )
      print(scores)
      # 처음 2줄만 조회
      print(scores.head(2))
      # 마지막 2줄만 조회
      print(scores.tail(2))

 

 

06. 데이터프레임 csv파일로 내보내기

  1. csv(comma separated values) 파일
    1. 표 형태의 데이터를 저장하는 파일 형식으로 다양한 분야에서 사용되며, 엑셀과 같은 스프레드시트 프로그램에서 편집이 가능함
  2. 앞 예제에서 사용한 성적정보를 csv파일로 내보내기
    1. 한글 깨짐 방지를 위해 encoding 옵션 필요
      ex04_pandas_csv.py
      
      import pandas as pd
      
      scores = pd.DataFrame(
          {
              "이름": ["김파이", "이파이", "박파이", "최파이", "정파이", "조파이"],
              "국어": [96, 76, 60, 85, 80, 100],
              "영어": [88, 92, 100, 55, 70, 100],
              "수학": [10, 20, 30, 40, 50, 100],
          }, index=[1, 2, 3, 4, 5, 6]
      )
      
      # 현재폴더에 scores.csv 라는 이름으로 파일 생성 
      scores.to_csv("./scores.csv", encoding="utf-8-sig")
    2. 생성된 파일 엑셀에서 열어본 화면

 

 

ch22 판다스로 크롤링 결과 저장하기

💡 이번 차시의 학습목표

✔ 인기급상승 동영상의 제목, 조회수 csv 파일로 저장

✔ 조회수 기준 내림차순으로 정렬하여 저장

01. 인기급상승 동영상 csv 파일로 저장하기

  1. 인기급상승 동영상 크롤링코드 활용
    driver = webdriver.Chrome()
    driver.get("<https://www.youtube.com/feed/trending>")
    time.sleep(2)
    elements = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
    time.sleep(2)
    hits_list = []
    title_list = []
    for element in elements:
        if element.get_attribute("aria-label"):
            hits_text = element.get_attribute("aria-label")
            start_index = hits_text.rfind("조회수")+4
            end_index = hits_text.rfind("회")
            hits = hits_text[start_index:end_index]
            hits = int(hits.replace(",", ""))
            title_list.append(element.text)
            hits_list.append(hits)
        else:
            print("조회수 데이터 없음")​
  2. 제목, 조회수 목록을 딕셔너리에 담기
    crawling_result = {
        "title": title_list,
        "hits": hits_list
    }
dataFrame = pd.DataFrame(title_list)
dataFrame.to_csv("result.csv", encoding="utf-8-sig")
  1. csv 파일 저장 결과(Visual Studio Code에서 실행)
  2. 조회수 내림차순으로 정렬하여 저장하기
    1. 판다스 sort_values() method 활용
      1. by=[”hits”] 로 조회수 기준으로 정렬, ascending=False로 내림차순
      2. 정렬 및 csv저장을 한문장으로 작성
        dataFrame.sort_values(by=["hits"], ascending=False).to_csv("result.csv", encoding="utf-8-sig")
  3. 무한 스크롤 적용하기
    1. 진행 순서
      1. 인기 급상승 페이지 접속
      2. 무한스크롤을 이용하여 전체 영상 로딩
      3. 크롤링 및 제목, 조회수 목록 생성
      4. csv로 저장

 

 

'Python' 카테고리의 다른 글

오늘의 블로그  (0) 2024.04.03
[Python] konlpy 형태소 분석  (0) 2024.03.22
[Python] 유튜브 크롤링(2)  (0) 2024.03.20
[Python] 유튜브 크롤링(1)  (0) 2024.03.19
[Python] Selenium 소개 및 사용법  (0) 2024.03.18

ch17 유튜브 크롤링-스크롤 제어

💡 이번 차시의 학습목표

✔ 현재 창의 높이 확인하기 위한 javascript 문법

✔ 스크롤을 제어하기 위한 javascript 문법

✔ selenium으로 javascript 문법 활용하여 스크롤 제어 하기

 

01. 스크롤 작업의 필요성

  1. 유튜브 홈페이지 또는 검색결과 페이지에는 모든 영상 콘텐츠가 한번에 노출되지 않음
  2. 스크롤을 내리는 과정에서 스크롤바가 페이지의 맨 하단까지 내려가게 되면 약간의 로딩 후 다음 영상 목록이 추가됨
  3. 영상 목록이 더 이상 추가되지 않을 때까지 내리기 위해선 스크롤을 계속해서 내려야 하는 노력과 시간 필요
  4. selenium, javascript 문법을 활용하여 모든 영상의 목록이 나올 때 까지 스크롤할 수 있도록 개발

02. 현재 열려있는 페이지의 높이 확인

  1. 브라우저에서 개발자도구 열고 Console 탭 열기
  2. 아래 코드 입력 후 결과 확인 (출력 숫자값은 다를 수 있음)
    1. 현재 브라우저에 열려 있는 페이지의 높이값을 가져오는 javascript 문법
      document.documentElement.scrollHeight​


  3. 스크롤을 제일 하단으로 내린 뒤 위의 코드 다시 입력 후 확인

 

 

03. selenium으로 페이지 높이 가져오는 내용 구현

  1. execute_script() method
    1. javascript 문법을 실행할 수 있도록 하는 method
    2. 매개값으로 javascript 코드 작성
  2. 페이지 높이 가져오는 문법 적용
    driver.execute_script("document.documentElement.scrollHeight")
  3. 앞의 문장으로는 확인할 수 있는 내용은 없으며, 파이썬 변수로 담아서 print() 수행하기 위한 코드로 수정
    1. return 이 추가된 이유는 javascript 문장을 수행후 반환되는 값을 가져오기 위함
    2. 반환값을 h1 변수에 담고 print()로 확인
      h1 = driver.execute_script("return document.documentElement.scrollHeight") print(h1)

 

 

03-1. 실습 예제

📥실습 코드

ex01_scroll.py

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("<https://www.youtube.com/>")
# driver.execute_script("document.documentElement.scrollHeight")
h1 = driver.execute_script("return document.documentElement.scrollHeight")
print(h1)

04. 스크롤 내리기

  1. 개발자 도구 Console 열기
  2. 스크롤을 제어하기 위한 javascript 문법
    1. 브라우저에 대한 제어가 필요하기 때문에 window 객체 사용
    2. scrollTo(x, y): 지정한 가로(x), 세로(y)위치로 스크롤을 이동시키는 함수
      1. 가로 스크롤은 0으로 고정 시키며, 세로 스크롤 값을 조정
    3. 아래와 같은 값을 console에 입력 후 각각 실행하며 스크롤의 위치 변화 확인
      window.scrollTo(0, 30) 
      window.scrollTo(0, 100) 
      window.scrollTo(0, 1000)
  3. 스크롤을 가장 하단으로 내리기
    1. 현재 열려있는 페이지의 높이만큼 스크롤을 내리도록 함
      1. 세로 값을 현재 열려있는 페이지 높이로 지정
        window.scrollTo(0, document.documentElement.scrollHeight)

05. selenium으로 스크롤 내리기 구현

  1. javascript 문법 사용을 위해 execute_script() 사용
    1. 유튜브 홈페이지 접속 후 페이지 높이 확인 후, 페이지 높이만큼 스크롤을 내리기 위한 함수 실행
      # 처음 페이지 높이 가져오기 
      h1 = driver.execute_script("return document.documentElement.scrollHeight")
      print(h1)
      # 페이지 높이 만큼 스크롤 내리기
      driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
  2. 같은 동작 2번 더 실행 후 콘솔에 출력된 페이지 높이값이 점점 증가하는지 확인
    1. 스크롤을 내리는데에 약간의 로딩시간이 필요하므로 스크롤 내린 뒤 time.sleep 을 활용하여 2초의 대기시간 추가
      # 처음 페이지 높이 가져오기 
      h1 = driver.execute_script("return document.documentElement.scrollHeight")
      print(h1)
      # 페이지 높이 만큼 스크롤 내리기
      driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
      # 약간의 로딩시간
      time.sleep(2)
      # 스크롤을 한 번 내린 뒤의 페이지 높이 가져오기 
      h2 = driver.execute_script("return document.documentElement.scrollHeight")
      print(h2)
      # 두번째 스크롤 내리는 동작
      driver.execute_script("window.scrollTo(0,document.documentElement.scrollHeight)")
      time.sleep(2)
      # 두 번 스크롤 내린 뒤의 페이지 높이 가져오기 
      h3 = driver.execute_script("return document.documentElement.scrollHeight")
      print(h3)
      time.sleep(3)

 

 

05-1. 실습 예제

📥실습 코드

ex02_scroll.py

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get("<https://www.youtube.com/>")

# 처음 페이지 높이 가져오기 
h1 = driver.execute_script("return document.documentElement.scrollHeight")
print(h1)
# 페이지 높이 만큼 스크롤 내리기
driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
# 약간의 로딩시간
time.sleep(2)
# 스크롤을 한 번 내린 뒤의 페이지 높이 가져오기 
h2 = driver.execute_script("return document.documentElement.scrollHeight")
print(h2)
# 두번째 스크롤 내리는 동작
driver.execute_script("window.scrollTo(0,document.documentElement.scrollHeight)")
time.sleep(2)
# 두 번 스크롤 내린 뒤의 페이지 높이 가져오기 
h3 = driver.execute_script("return document.documentElement.scrollHeight")
print(h3)
time.sleep(3)
  1.  

ch18 유튜브 크롤링-무한 스크롤

💡 이번 차시의 학습목표

✔ 무한 스크롤을 이용하여 유튜브 영상 목록을 모두 불러옴

✔ 영상의 제목 크롤링

01. 무한 스크롤 동작을 위한 방법

  1. 유튜브 홈페이지 접속 후 모든 영상목록을 보려면 스크롤을 계속해서 내려야 모든 영상을 불러올 수 있음
  2. 하지만 검색어에 따라 영상의 갯수는 다르기 때문에 몇 회를 반복하거나 몇 분 동안 반복하는 방식은 적절하지 않음
  3. 페이지 높이를 확인하는 방식을 이용하여 스크롤 수행하는 절차
    1. 스크롤 수행 전 높이 확인
    2. 스크롤 한 번 수행
    3. 스크롤 수행 후 페이지의 높이와 스크롤 수행 전 페이지의 높이 비교
      1. 스크롤 수행 후의 페이지 높이가 크면 스크롤 수행
      2. 두 값이 일치한다면 스크롤 중단

02. 무한 스크롤 코드 구현하기

  1. 스크롤은 계속 반복적으로 수행되어야 하기 때문에 반복문 활용
    1. 횟수가 정해져 있지 않으므로 while문 활용
    while True:
    	# 반복문 내용
    
  2. 스크롤을 수행하기 전 페이지의 높이 가져오기
  3. before_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
  4. 페이지 높이만큼 스크롤 내리기
  5. driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
  6. 스크롤 수행 후 페이지 높이 가져오기
  7. after_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
  8. 스크롤 수행 전, 후 페이지 높이 비교
    1. 높이가 동일하면 더이상 스크롤이 내려갈 수 없다 판단하여 while문 종료
    if before_scroll_height == after_scroll_height:
            break
    

02-1. 실습 코드

<aside> 📌 실습코드는 코드박스에서 확인해주세요!

</aside>

  1. 스크롤을 내린 후 2초씩의 대기 시간을 적용함
  2. 모든 스크롤이 내려갔는지 확인을 위해 while문 종료 후 10초의 대기시간 적용

📥실습 코드

ex01_scroll.py

from selenium import webdriver
import time

driver = webdriver.Chrome()
driver.get("<https://www.youtube.com/>")

while True:
    before_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
    driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
    time.sleep(2)
    after_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
    time.sleep(2)
    if before_scroll_height == after_scroll_height:
        break
    # else:
    #     before_scroll_height = after_scroll_height

time.sleep(10)

03. 스크롤 완료 후 영상의 제목만 가져오기

  1. find_elements() 를 활용하여 제목을 가져온 뒤 for문으로 출력
    1. 제목 가져오는 방법은 이전 차시에서 배웠던 방식과 동일함
    2. 영상 갯수 확인을 위해 len() 함수 활용
    titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
    print("영상 갯수: ", len(titles))
    for title in titles:
        print(title.text)
    

04. 무한 스크롤 코드 함수화하기

  1. 스크롤 부분만 함수로 정의
    ex02_scroll_function_01.py
    
    from selenium import webdriver
    import time
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get("https://www.youtube.com/")
    
    def scroll():
        while True:
            before_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
            time.sleep(2)
            after_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
            time.sleep(2)
            if before_scroll_height == after_scroll_height:
                break
        time.sleep(2)
    
    scroll()
    titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
    print("영상 갯수: ", len(titles))
    for title in titles:
        print(title.text)
  2. 스크롤 후 제목 list 반환하는 내용을 함수로 정의
    ex02_scroll_function_02.py
    
    from selenium import webdriver
    import time
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get("https://www.youtube.com/")
    
    def scroll():
        while True:
            before_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
            time.sleep(2)
            after_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
            time.sleep(2)
            if before_scroll_height == after_scroll_height:
                break
        time.sleep(2)
        titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
        print("영상 갯수: ", len(titles))
        return titles
    
    titles = scroll()
    
    for title in titles:
        print(title.text)


ch19 유튜브 크롤링-검색 필터링

💡 이번 차시의 학습목표

✔ 인기급상승 동영상 제목 크롤링

✔ 검색어 입력 후 필터 적용하여 제목 크롤링

01. 유튜브 인기급상승 페이지 영상 제목 크롤링

  1. 접속 주소: 🌐 https://www.youtube.com/feed/trending
  2. 이전 차시에서 진행한 코드에서 주소만 적용하여 진행 가능
    ex01_trending.py
    
    from selenium import webdriver
    import time
    from selenium.webdriver.common.by import By
    
    driver = webdriver.Chrome()
    driver.get("https://www.youtube.com/feed/trending")
    
    def scroll():
        while True:
            before_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
            driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
            time.sleep(2)
            after_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
            time.sleep(2)
            if before_scroll_height == after_scroll_height:
                break
        time.sleep(2)
        titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
        print("영상 갯수: ", len(titles))
        return titles
    
    titles = scroll()
    
    for title in titles:
        print(title.text)

 

02. 유튜브 검색 결과 조회수순 필터링을 위한 요소 확인하기

  1. 유튜브 검색화면 살펴보기
    1. 검색 결과 화면에서 아래 그림과 같이 ‘필터’를 클릭하면 업로드 날짜, 구분, 길이, 정렬기준 등을 선택할 수 있는 메뉴가 노출됨
    2. 정렬기준의 조회수를 클릭하면 검색 결과가 조회수가 높은순으로 영상목록 정렬됨
  2. 앞서 진행한 방법을 selenium으로 구현하기 위해 필터, 조회수 클릭 요소 살펴보기
    1. 필터 버튼 요소 확인하기
      1. ‘**개발자도구’**를 열고 필터 버튼의 요소 확인
      2. 복사한 요소
        <ytd-toggle-button-renderer align-by-text="" class="style-scope ytd-search-sub-menu-renderer" button-renderer="true"><yt-button-shape><button class="yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-leading yt-spec-button-shape-next--align-by-text " aria-pressed="false" aria-label="검색 필터" style=""><div class="yt-spec-button-shape-next__icon" aria-hidden="true"><yt-icon style="width: 24px; height: 24px;"><svg viewBox="0 0 24 24" preserveAspectRatio="xMidYMid meet" focusable="false" class="style-scope yt-icon" style="pointer-events: none; display: block; width: 100%; height: 100%;"><g class="style-scope yt-icon"><path d="M15,17h6v1h-6V17z M11,17H3v1h8v2h1v-2v-1v-2h-1V17z M14,8h1V6V5V3h-1v2H3v1h11V8z M18,5v1h3V5H18z M6,14h1v-2v-1V9H6v2H3v1 h3V14z M10,12h11v-1H10V12z" class="style-scope yt-icon"></path></g></svg><!--css-build:shady--></yt-icon></div><div class="cbox yt-spec-button-shape-next--button-text-content"><span class="yt-core-attributed-string yt-core-attributed-string--white-space-no-wrap" role="text">필터</span></div><yt-touch-feedback-shape style="border-radius: inherit;"><div class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response" aria-hidden="true"><div class="yt-spec-touch-feedback-shape__stroke" style=""></div><div class="yt-spec-touch-feedback-shape__fill" style=""></div></div></yt-touch-feedback-shape></button></yt-button-shape>
        <tp-yt-paper-tooltip fit-to-visible-bounds="" offset="8" role="tooltip" tabindex="-1" style="inset: 60px auto auto 7px;"><!--css-build:shady--><div id="tooltip" class="style-scope tp-yt-paper-tooltip hidden" style-target="tooltip">
          검색 필터 열기
        </div>
        </tp-yt-paper-tooltip>
        </ytd-toggle-button-renderer>​​
    2. 필터에서 조회수 요소 확인하기
      1. 개발자도구에서 확인
      2. 복사한 요소
        <a id="endpoint" class="yt-simple-endpoint style-scope ytd-search-filter-renderer" href="/results?search_query=%EB%89%B4%EC%A7%84%EC%8A%A4&amp;sp=CAM%253D">
        <div id="label" class="style-scope ytd-search-filter-renderer" title="조회수순 정렬">
            <yt-formatted-string class="style-scope ytd-search-filter-renderer">조회수</yt-formatted-string>
            <yt-icon id="dismiss-x" icon="yt-icons:dismissal" class="style-scope ytd-search-filter-renderer"><svg viewBox="0 0 24 24" preserveAspectRatio="xMidYMid meet" focusable="false" class="style-scope yt-icon" style="pointer-events: none; display: block; width: 100%; height: 100%;"><g class="style-scope yt-icon"><path d="M12.7,12l6.6,6.6l-0.7,0.7L12,12.7l-6.6,6.6l-0.7-0.7l6.6-6.6L4.6,5.4l0.7-0.7l6.6,6.6l6.6-6.6l0.7,0.7L12.7,12z" class="style-scope yt-icon"></path></g></svg><!--css-build:shady--></yt-icon>
          </div>
        </a>

 

 

 

 

03. selenium으로 검색 결과에서 조회수순 정렬 과정 구현하기

  1. selenium으로 필터 버튼 클릭하기
    1. 필터 버튼의 xpath 복사하여 find_element() 로 접근
    2. 가져온 요소 click() 으로 클릭
      # 영상에서의 코드 
      filter_button = driver.find_element(By.XPATH, '//*[@id="container"]/ytd-toggle-button-renderer')
      
      # 수정된 코드 
      filter_button = driver.find_element(By.XPATH, '//*[@id="filter-button"]')
      
      filter_button.click()
      
  2. selenium으로 조회수 클릭하기
    1. 조회수의 full xpath 복사하여 find_element() 로 접근
      1. 관련성, 업로드날짜, 조회수, 평점이 모두 같은 xpath, css_selector값을 갖고 있어 구분이 제대로 되지 않아 full xpath 복사하여 사용
    2. 가져온 요소 click() 으로 클릭
      # 영상에서의 코드 
      hits_button = driver.find_element(By.XPATH, '/html/body/ytd-app/div[1]/ytd-page-manager/ytd-search/div[1]/ytd-two-column-search-results-renderer/div/ytd-section-list-renderer/div[1]/div[2]/ytd-search-sub-menu-renderer/div[1]/iron-collapse/div/ytd-search-filter-group-renderer[5]/ytd-search-filter-renderer[3]/a')
      
      # 수정된 코드
      hits_button = driver.find_element(By.XPATH, '/html/body/ytd-app/ytd-popup-container/tp-yt-paper-dialog/ytd-search-filter-options-dialog-renderer/div[2]/ytd-search-filter-group-renderer[5]/ytd-search-filter-renderer[3]/a')
      
      hits_button.click()
      

04. 정렬된 결과에서 무한 스크롤 수행 후 영상 제목 크롤링 수행

05. 실습 예제

<aside> 📌 실습코드는 코드박스에서 확인해주세요!

</aside>

📥실습 코드

ex02_search_filter.py

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time

def scroll():
    while True:
        before_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
        driver.execute_script("window.scrollTo(0, document.documentElement.scrollHeight)")
        time.sleep(2)
        after_scroll_height = driver.execute_script("return document.documentElement.scrollHeight")
        time.sleep(2)
        if before_scroll_height == after_scroll_height:
            break
    time.sleep(2)
    titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
    print("영상 갯수: ", len(titles))
    return titles

# 브라우저 실행
driver = webdriver.Chrome()
driver.get("<https://www.youtube.com/>")
search_input = driver.find_element(By.CSS_SELECTOR, "input#search")
search_input.send_keys("뉴진스")
# 검색버튼 클릭
search_button = driver.find_element(By.CSS_SELECTOR, "button#search-icon-legacy")
search_button.click()
time.sleep(2)
# 필터버튼 클릭
filter_button = driver.find_element(By.XPATH, '//*[@id="container"]/ytd-toggle-button-renderer')
filter_button.click()
time.sleep(2)
# 조회수 클릭
hits_button = driver.find_element(By.XPATH, '/html/body/ytd-app/div[1]/ytd-page-manager/ytd-search/div[1]/ytd-two-column-search-results-renderer/div/ytd-section-list-renderer/div[1]/div[2]/ytd-search-sub-menu-renderer/div[1]/iron-collapse/div/ytd-search-filter-group-renderer[5]/ytd-search-filter-renderer[3]/a')
hits_button.click()
time.sleep(2)
# 무한 스크롤 함수 호출
titles = scroll()

for title in titles:
    print(title.text)

 

 

ch20 유튜브 크롤링-검색 및 스크롤 적용

💡 이번 차시의 학습목표

✔ 인기급상승 동영상을 크롤링하여 제목, 조회수 출력하기

✔ 제목, 조회수 따로 리스트에 저장하기

01. 조회수 값 가져오기

  1. 조회수 표현 요소 확인
    1. 아래 그림과 같이 영상 제목 요소의 a태그 aria-label 속성에서 조회수 값을 확인할 수 있음
    2. aria-label 속성 값
    3. 다나카 초대석 게시자: 침착맨 1일 전 50분 조회수 939,511회
    4. 조회수 값만 표현하는 부분이 없기 때문에 위의 텍스트에서 조회수 숫자만 따로 가져와야 함
  2. 조회수 값을 가져오기 위한 과정</aside>
    1. rfind() method 활용
      1. 해당 변수의 마지막에서 찾기 시작하여 매개변수로 지정한 값이 시작되는 인덱스 값을 반환해줌
        1. find() method는 앞에서부터 찾기 때문에 제목에 ‘조회수’라는 글자가 포함된 경우라면 다른 결과가 나올 수 있음
      2. 조회수 텍스트가 있는 인덱스 찾기
        hits_text.rfind("조회수")
    2. 조회수 값 시작 인덱스 찾기
      1. 조회수로 부터 4번째 인덱스 부터 조회수 값이 작성되어 있음.
        hits_text.find("조회수")+4
    3. 조회수 값 마지막 인덱스 찾기
      1. ‘회’라는 글자 앞까지가 조회수값이 끝나는 인덱스
        hits_text.find("회")
    4. 시작인덱스, 끝 인덱스 값을 활용하여 조회수 숫자만 가져오기
      start_index = hits_text.rfind("조회수")+4
      end_index = hits_text.rfind("회")
      print(hits_text[start_index:end_index])
    5. 구분자 쉼표 제거 후 정수로 변환
      1. 조회수순 정렬 등을 위해선 정수형태의 자료형으로 변환 필요
        hits = hits_text[start_index:end_index]
        hits = int(hits.replace(",", ""))

02. 크롤링 코드에 적용하기

 

  1. 제목, 조회수를 담을 리스트 각각 선언
    hits_list = []
    title_list = []
  2. aria-label 속성값 가져오기
    hits_text = element.get_attribute("aria-label")
  3. 인기급상승 Shorts 의 경우 구조가 달라서 제외
    1. 제외하기 위해 조건문 활용
      if element.get_attribute("aria-label"):
  4. 조회수 값을 가져오기 위한 코드
    1. 조회수 값을 추출한 뒤 제목, 조회수 값을 각각 리스트에 저장
      hits_text = element.get_attribute("aria-label")
      start_index = hits_text.rfind("조회수")+4
      end_index = hits_text.rfind("회")
      hits = hits_text[start_index:end_index]
      hits = int(hits.replace(",", ""))
      title_list.append(element.text)
      hits_list.append(hits)
  5. 완료 후 출력하여 확인
    1. 두 개 리스트를 동시에 반복문으로 사용하기 위해 zip() 활용
      for title, hits in zip(title_list, hits_list):
          print(title, hits)

 

 

 

'Python' 카테고리의 다른 글

[Python] konlpy 형태소 분석  (0) 2024.03.22
[Python] 판다스 Pandas  (1) 2024.03.21
[Python] 유튜브 크롤링(1)  (0) 2024.03.19
[Python] Selenium 소개 및 사용법  (0) 2024.03.18
[Python] 패키지 설치 및 numpy, matplotlib 기초  (0) 2024.03.15

ch14 크롤링 시작하기

💡 이번 차시의 학습목표

✔ 크롤링 실습하기

  • 다나와 - 상품목록 크롤링하기
  • 네이버웹툰 - 웹툰 제목 크롤링하기

01. 다나와 상품 목록 크롤링하기

  1. 검색주소값 가져오기
    1. 다나와 홈페이지 접속
      1. https://www.danawa.com/
    2. 검색창에 노트북 입력 후 검색버튼 클릭
    3. 검색 링크
      1. https://prod.danawa.com/list/?cate=112758&shortcutKeyword=노트북
  2. 상품명 요소 확인하기
    1. 검색 결과에서 상단에는 광고상품이 노출되는데 광고상품은 제외함
    2. 개발자도구 열고 노트북 이름을 표시하는 요소 확인

      <a href="https://prod.danawa.com/info/?pcode=17980199&amp;cate=112758" 
      		target="_blank" onmousedown="_trkEventLog('15상품리스트_상품명')" 
      		name="productName">에이서 니트로 5 AN515-58-94SX</a>​
  3. selenium으로 요소 접근하기
    1. 상품명은 a 태그의 text 속성 형태로 표현되어 있음.
    2. 해당 태그에는 class, id와 같은 속성은 없으며, name=productName 속성 있음.
    3. name 속성을 활용하여 접근
    4. name속성은 By.CSS_SELECTOR 이용
      1. 사용문법
        1. find_elements(By.CSS_SELECTOR, ‘[name=”productName”]’)
        2. 내용이 여러 개이므로 find_elements 사용
        3. [ ]부분을 감싸는 ‘(single quote), name값을 감싸는 “(double quote) 주의하여 작성
  4. 크롤링 데이터 확인하기
    1. 상품명 출력을 위해 for 문 활용

 

 

01-1. 실습 예제

📥실습 코드

ex01_crawling.py

from selenium import webdriver
from selenium.webdriver.common.by import By

# 다나와 상품목록 크롤링
# 브라우저 실행
driver = webdriver.Chrome()
# 접속
driver.get("<https://prod.danawa.com/list/?cate=112758&shortcutKeyword=%EB%85%B8%ED%8A%B8%EB%B6%81>")
notebook_names = driver.find_elements(By.CSS_SELECTOR, '[name="productName"]')
# print(notebook_names)
for name in notebook_names:
    # 코드값이 보임 
    # print(name)
    # 텍스트 출력하기
    print(name.text)

02. 네이버웹툰 웹툰 제목 크롤링하기

  1. 검색주소값 가져오기
    1. 네이버웹툰 홈페이지 접속
      1. https://comic.naver.com/webtoon/weekday
  2. 웹툰제목 요소 확인하기
    1. 전체 웹툰이 보이는 화면에서 월요웹툰 중 첫번째 웹툰의 제목 요소 확인
    2. 개발자도구 열고 웹툰제목을 표시하는 요소 확인
    📥실습 코드
    <a class="ContentTitle__title_area--x24vt" href="/webtoon/list?titleId=648419">
    <span class="ContentTitle__title--e3qXt">뷰티풀 군바리</span></a>​

    selenium으로 요소 접근하기
    1. 웹툰 제목은 a 태그에 표현되어 있고, class=”ContentTitle__title_area--x24vt” 속성을 가지고 있음.
    2. class=”ContentTitle__title_area--x24vt”로 속성 접근
    3. class속성은 By.CLASS_NAME 이용
      1. 사용문법
        1. find_elements(By.CLASS_NAME, ‘ContentTitle__title_area--x24vt’)
        2. 내용이 여러 개이므로 find_elements 사용
  3. 크롤링 데이터 확인하기
    1. 웹툰제목 출력을 위해 for 문 활용(웹툰 갯수가 578개로 출력에 1분이상 소요)

 

 

02-1. 실습 예제

📥실습 코드

ex02_crawling.py

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("<https://comic.naver.com/webtoon>")
time.sleep(2)
webtoon_titles = driver.find_elements(By.CLASS_NAME, 'ContentTitle__title_area--x24vt')
time.sleep(5)
for name in webtoon_titles:
    print(name.text)
print(len(webtoon_titles))

 

ch15 유튜브 크롤링-시작

💡 이번 차시의 학습목표

✔ 유튜브 홈페이지 구성요소 확인

✔ 유튜브 영상 제목 크롤링 하기

01. 유튜브 홈페이지 구조 살펴보기

  1. **홈페이지 주소: https://www.youtube.com/ 
  2. 크롬 개발자 도구 열어서 영상의 요소 확인
    1. 요소 선택을 위한 아이콘 클릭
    2. 유튜브 영상의 제목 부분 클릭하여 요소 확인
    3. 선택된 부분 마우스 우클릭하여 요소 복사 가능
      1. 예시에서 복사한 요소
        <yt-formatted-string id="video-title" class="style-scope ytd-rich-grid-media" aria-label="54톤 거대 고래 뱃속에서 발견된 것은? [국경없는 영상] 게시자:  YTN 2일 전 1분 54초 조회수 1,400,217회">54톤 거대 고래 뱃속에서 발견된 것은? [국경없는 영상]</yt-formatted-string>​

02. 제목 텍스트 표현 요소 접근하기

  1. 제목 텍스트 위치 확인
    1. 영상의 제목은 <yt-formatted-string></yt-formatted-string> 태그 내에 작성되어 있음
      1. yt- 또는 ytd- 로 시작하는 태그는 사용자 정의 요소(Custom Element)이며, selenium으로 요소를 가져올 때는 id, class 등 html 요소를 주로 이용
        1. 사용자 정의 요소: 표준 html 요소가 아니며, 특정 디자인이나 기능 등을 반복적으로 사용할 때 활용할 수 있음
  2. 제목 텍스트를 가져오기 위해 id=”video-title” 속성 활용
    1. selenium의 find_elements() method를 사용하여 전체 내용을 가져옴
      titles = driver.find_elements(By.ID, "video-title")


    2. XPATH로도 접근 가능
      1. “ ”, ‘ ’ 사용 위치 주의
      titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
  3. titles의 자료형 확인
    1. type 함수 사용하여 가져온 요소의 자료형 확인
      print(type(titles))
    2. list이기 때문에 내용을 확인하기 위해선 반복문을 활용해야 함

 

 

03. 제목 텍스트 출력하기

  1. list를 접근하기 위해 for문 활용하여 출력
    1. text 속성을 사용하여 제목값을 출력할 수 있음
      for title in titles:
      	print(title.text)
    2. 태그 이름 출력
      	print(title.tag_name)
    3. aria-label 속성값 출력
      	print(title.get_attribute("aria-label")

 

 

 

04. 실습 예제

📥실습 코드

ex01_youtube.py

from selenium import webdriver
from selenium.webdriver.common.by import By

# 브라우저 실행
driver = webdriver.Chrome()
driver.get("<https://www.youtube.com/>")
# titles = driver.find_elements(By.ID, "video-title")
titles = driver.find_elements(By.XPATH, '//*[@id="video-title"]')
print(titles)
print(type(titles))
for title in titles:
    print(title.tag_name) # 태그 이름 가져오기
    print(title.text) # inner HTML 값 가져오기
    print(title.get_attribute("aria-label")) # 속성값 가져오기

 

 

ch16 유튜브 크롤링-검색 기능 활용

💡 이번 차시의 학습목표

✔ 검색어를 입력하여 검색된 영상의 제목 크롤링 하기

✔ selenium으로 검색창, 검색버튼 사용하기

01. 유튜브 검색 환경 살펴보기

  1. 유튜브 검색창에 ‘뉴진스’ 입력 후 검색
  2. 검색과정
    1.검색창에 검색어(키워드) 입력 → 🔍검색 버튼 또는 엔터 입력
 
 

02. 검색하는 과정 selenium으로 구현해보기

  1. 과정
    1. selenium으로 유튜브 홈페이지 접속
    2. 검색창 요소 접근
    3. 검색어 입력하기
    4. 검색 버튼 클릭하기 또는 엔터키 입력
    1. selenium으로 유튜브 홈페이지 접속
      driver.get("https://www.youtube.com/")​
    2. 검색어 입력 요소 접근
      1. 검색어 입력창 요소 확인
        1. 개발자 도구 열어서 검색어 입력창 클릭
        2. input 태그이며, id=”search” 속성이 적용되어 있음
          <input id="search" autocapitalize="none" autocomplete="off" autocorrect="off" name="search_query" tabindex="0" type="text" spellcheck="false" placeholder="검색" aria-label="검색" role="combobox" aria-haspopup="false" aria-autocomplete="list" class="gsfi ytd-searchbox" dir="ltr" style="border: none; padding: 0px; margin: 0px; height: auto; width: 100%; outline: none;">
      2. selenium으로 검색어 입력창 가져오기
        1. css 선택자로 접근(id=”search” 가 적용된 input 태그)
          search_input = driver.find_element(By.CSS_SELECTOR, "input#search")
    3. 검색어 입력하기
      1. selenium의 send_keys() method를 이용하여 검색어 입력
        search_input.send_keys("뉴진스")
    4. 검색버튼 클릭하기
      1. 검색버튼 요소 확인
        • 개발자도구에서 검색 버튼 요소 확인
          <button id="search-icon-legacy" class="style-scope ytd-searchbox" aria-label="검색">
            <yt-icon class="style-scope ytd-searchbox"><svg viewBox="0 0 24 24" preserveAspectRatio="xMidYMid meet" focusable="false" class="style-scope yt-icon" style="pointer-events: none; display: block; width: 100%; height: 100%;"><g class="style-scope yt-icon"><path d="M20.87,20.17l-5.59-5.59C16.35,13.35,17,11.75,17,10c0-3.87-3.13-7-7-7s-7,3.13-7,7s3.13,7,7,7c1.75,0,3.35-0.65,4.58-1.71 l5.59,5.59L20.87,20.17z M10,16c-3.31,0-6-2.69-6-6s2.69-6,6-6s6,2.69,6,6S13.31,16,10,16z" class="style-scope yt-icon"></path></g></svg><!--css-build:shady--></yt-icon>
            <tp-yt-paper-tooltip prefix="" class="style-scope ytd-searchbox" role="tooltip" tabindex="-1" style="left: 815.5px; top: 62px;"><!--css-build:shady--><div id="tooltip" class="style-scope tp-yt-paper-tooltip hidden" style-target="tooltip">
            검색
          </div>
          </tp-yt-paper-tooltip>
          </button>
      2. selenium으로 검색 버튼 접근
        • css 선택자로 접근
          search_button = driver.find_element(By.CSS_SELECTOR, "button#search-icon-legacy")
      3. 검색 버튼 클릭하기
        search_button.click()
    5. 검색어 입력 후 엔터 입력으로 검색하기
      1. 검색어 입력까지의 과정은 동일
      2. 검색어 입력 후 엔터키 입력 동작을 위해 Keys 라이브러리 추가
        from selenium.webdriver.common.keys import Keys
      3. 검색어 입력 및 엔터 입력
        search_input.send_keys("뉴진스")
        search_input.send_keys(Keys.RETURN)​

        ex01_search.py
        
        from selenium import webdriver
        from selenium.webdriver.common.by import By
        from selenium.webdriver.common.keys import Keys
        import time
        
        # 브라우저 실행
        driver = webdriver.Chrome()
        driver.get("https://www.youtube.com/")
        search_input = driver.find_element(By.CSS_SELECTOR, "input#search")
        # print(search_input.tag_name)
        search_input.send_keys("뉴진스")
        # 검색버튼 클릭
        search_button = driver.find_element(By.CSS_SELECTOR, "button#search-icon-legacy")
        search_button.click()
        time.sleep(2)
        # 엔터키 입력
        # search_input.send_keys(Keys.RETURN)
        titles = driver.find_elements(By.ID, "video-title")
        for title in titles:
            print(title.text)

03. 다른 방법으로 검색 결과 가져오기

  1. 유튜브 검색 시 브라우저의 주소값 살펴보기
    1. ‘뉴진스’ 검색하는 경우 주소값
      1. https://www.youtube.com/results?search_query=뉴진스
    2. ‘bts’ 검색하는 경우 주소값
      1. https://www.youtube.com/results?search_query=bts
  2. 주소값 분석
    1. https://www.youtube.com/results?search_query=’ 부분은 동일하며 search_query=’검색어’ 형태로 검색어에 따라 마지막 부분만 바뀜
  3. selenium으로 주소값에 검색어를 포함하여 시작
    1. ‘뉴진스’ 검색결과 페이지로 직접 접속
      driver.get("https://www.youtube.com/results?search_query=뉴진스")
    2. 실습코드
      ex02_search.py
      
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.common.keys import Keys
      import time
      
      driver = webdriver.Chrome()
      driver.get("<https://www.youtube.com/results?search_query=뉴진스>")
      
      titles = driver.find_elements(By.ID, "video-title")
      for title in titles:
          print(title.text)
      ​
  4. 검색어를 콘솔로 입력받아 적용하기
    1. input 함수로 입력값 변수로 가져오기(아래 문장이 가장 먼저 실행되어야 함)
      q = input("검색어를 입력하세요: ")

      검색어를 요청 주소에 추가하기
      1. ‘+’ 를 이용하여 연결
        driver.get("<https://www.youtube.com/results?search_query=>"+q)
    2. 실습코드
      ex03_search.py
      
      from selenium import webdriver
      from selenium.webdriver.common.by import By
      from selenium.webdriver.common.keys import Keys
      import time
      
      q = input("검색어를 입력하세요: ")
      driver = webdriver.Chrome()
      driver.get("<https://www.youtube.com/results?search_query=>"+q)
      
      titles = driver.find_elements(By.ID, "video-title")
      for title in titles:
          print(title.text)
      ​

 

 

'Python' 카테고리의 다른 글

[Python] 판다스 Pandas  (1) 2024.03.21
[Python] 유튜브 크롤링(2)  (0) 2024.03.20
[Python] Selenium 소개 및 사용법  (0) 2024.03.18
[Python] 패키지 설치 및 numpy, matplotlib 기초  (0) 2024.03.15
[Python] 함수와 모듈  (0) 2024.03.11

+ Recent posts