{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## HTML을 parsing 하기 - 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### BeautifulSoup4 설치."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting bs4\n",
      "Requirement already satisfied: beautifulsoup4 in c:\\anaconda3\\lib\\site-packages (from bs4) (4.6.0)\n",
      "Installing collected packages: bs4\n",
      "Successfully installed bs4-0.0.1\n"
     ]
    }
   ],
   "source": [
    "!pip install bs4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import bs4\n",
    "import os"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. BeautifulSoup 객체로 변환하여 parsing 하도록 한다:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "os.chdir(r\"C:\\Users\\Gram\\Desktop\\myPyCode\\02  데이터 수집과 처리 - 실습\\data\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "#컴퓨터에 저장된 html파일로 parshing하기위해 파일 읽어오기\n",
    "f = open(\"page_02b.html\",\"r\")\n",
    "my_html = f.read()\n",
    "f.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<!DOCTYPE HTML>\n",
      "<html lang=\"“en”\">\n",
      " <!-- 이 행은 주석. -->\n",
      " <head>\n",
      "  <meta content=\"text/html; charset=utf-8\"/>\n",
      "  <title>\n",
      "   CSS 셀렉터 예문 2\n",
      "  </title>\n",
      " </head>\n",
      " <!--  여기까지가 헤드. -->\n",
      " <!-- style 정의! -->\n",
      " <style>\n",
      "  .myClass1 {\n",
      "\tcolor:blue;\n",
      "\tbackground-color:gray;\n",
      "\tfont-weight:bolder;\n",
      "    }\n",
      "\n",
      ".myClass2 {\n",
      "\tcolor:red;\n",
      "\tbackground-color:yellow;\n",
      "\tfont-weight:lighter;\n",
      "    }\n",
      "\n",
      ".myClass3 {\n",
      "\tcolor:green;\n",
      "\tbackground-color:orange;\n",
      "\tfont-weight:normal;\n",
      "    }\n",
      "\n",
      "div.myClass3 {\n",
      "\tcolor:white;\n",
      "\tbackground-color:black;\n",
      "\tfont-weight:normal;\n",
      "    }\n",
      "\n",
      "li.myClass3 {\n",
      "\tcolor:gray;\n",
      "\tbackground-color:red;\n",
      "\tfont-weight:bolder;\n",
      "    }\n",
      "\n",
      "#myID1 {\n",
      "\tcolor:yellow;\n",
      "\tbackground-color:violet;\n",
      "\tfont-weight:bolder;\n",
      "    }\n",
      "\n",
      "#myID2 {\n",
      "\tcolor:yellow;\n",
      "\tbackground-color:blue;\n",
      "\tfont-weight:bolder;\n",
      "    }\n",
      " </style>\n",
      " <body>\n",
      "  <h1 class=\"myClass1\">\n",
      "   헤더 1.1\n",
      "  </h1>\n",
      "  <h1 class=\"myClass2\">\n",
      "   헤더 1.2\n",
      "  </h1>\n",
      "  <h1 class=\"myClass3\">\n",
      "   헤더 1.3\n",
      "  </h1>\n",
      "  <h2 class=\"myClass1\">\n",
      "   헤더 1.1\n",
      "  </h2>\n",
      "  <h2 class=\"myClass2\">\n",
      "   헤더 1.2\n",
      "  </h2>\n",
      "  <h2 class=\"myClass3\">\n",
      "   헤더 1.3\n",
      "  </h2>\n",
      "  <p class=\"myClass1\">\n",
      "   Paragraph 1.\n",
      "  </p>\n",
      "  <p class=\"myClass2\" id=\"myID1\">\n",
      "   Paragraph 2.\n",
      "  </p>\n",
      "  <p class=\"myClass3\">\n",
      "   Paragraph 3.\n",
      "  </p>\n",
      "  <div class=\"myClass3\">\n",
      "   <br/>\n",
      "   <span>\n",
      "    A Single line within a div tag.\n",
      "   </span>\n",
      "   <br/>\n",
      "   <p class=\"myClass1\">\n",
      "    Paragraph 4.\n",
      "   </p>\n",
      "   <p class=\"myClass2\">\n",
      "    Paragraph 5.\n",
      "   </p>\n",
      "   <p class=\"myClass3\">\n",
      "    Paragraph 6.\n",
      "   </p>\n",
      "   <br/>\n",
      "  </div>\n",
      "  <br/>\n",
      "  <div>\n",
      "   <br/>\n",
      "   다음은 ordered list이다:\n",
      "   <ol>\n",
      "    <li class=\"myClass1\">\n",
      "     아이템 하나.\n",
      "    </li>\n",
      "    <li class=\"myClass2\">\n",
      "     아이템 둘.\n",
      "    </li>\n",
      "    <li class=\"myClass3\" id=\"myID2\">\n",
      "     아이템 셋.\n",
      "    </li>\n",
      "    <li class=\"myClass1\">\n",
      "     아이템 넷.\n",
      "    </li>\n",
      "    <li class=\"myClass2\">\n",
      "     아이템 다섯.\n",
      "    </li>\n",
      "    <li class=\"myClass3\">\n",
      "     아이템 여섯.\n",
      "    </li>\n",
      "   </ol>\n",
      "   <br/>\n",
      "  </div>\n",
      " </body>\n",
      " <!-- 여기까지가 몸통. -->\n",
      "</html>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 3 가지 parser 중 'html.parser' 선택\n",
    "soup = bs4.BeautifulSoup(my_html, 'html.parser')     #res.text가 텍스트(문자열), BeautifulSoup4로 파싱해 soup객체로 변환시킴 \n",
    "                                                     #soup객체 생성 \n",
    "print(soup.prettify())  #soup객체에서 prettify메서드 사용(조금 더 읽기 쉬운 형태로 출력위해)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1 BeautifulSoup4 라이브러리로 parsing을 한다: p태그"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Paragraph 1.\n"
     ]
    }
   ],
   "source": [
    "# 첫 번째 <p> 태그를 찾아서 출력한다.\n",
    "x=soup.find('p')                #첫번째 p태그를 가져옴\n",
    "print(x.text.strip())           #p태그 텍스트에서 strip"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Paragraph 1.\n",
      "\n",
      "Paragraph 2.\n",
      "\n",
      "Paragraph 3.\n",
      "\n",
      "Paragraph 4.\n",
      "\n",
      "Paragraph 5.\n",
      "\n",
      "Paragraph 6.\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 모든 <p> 태그의 내용을 찾아서 이어 붙여 출력한다.\n",
    "x=soup.find_all('p')    #모든 p태그 가져오기    #x는 리스트성격\n",
    "n = len(x)              #길이로 x의 원소개수 확인\n",
    "result = ''             #빈 문자열 만들어 원소 하나하나 가져옴     # 초기화.\n",
    "\n",
    "#x[i]태그객체를 가져와 text속성가져옴\n",
    "for i in range(n):\n",
    "    result += x[i].text.strip() + '\\n\\n'    #문자열 메서드 strip(왼쪽 오른쪽 스페이스 떨궈줌)\n",
    "                                            #\\n\\n(라인 체인지), +(두개 연결)\n",
    "                                            \n",
    "# 출력.\n",
    "print(result)     #p태그 안에 있는 내용만 나옴"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(x)           #결과값 ResultSet은 리스트형태로 나옴: 인덱싱해서 원소 가져올 수 있음\n",
    "type(x[0])        #첫번째 원소 가져옴\n",
    "\n",
    "for i in range(n):\n",
    "    result += x[i].text.strip()  #인덱싱해 원소가져옴"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 BeautifulSoup4 라이브러리로 parsing을 한다: div태그"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A Single line within a div tag. \n",
      "\n",
      " Paragraph 4. \n",
      " Paragraph 5. \n",
      " Paragraph 6.\n",
      "\n",
      "다음은 ordered list이다:\n",
      "\n",
      " 아이템 하나. \n",
      " 아이템 둘. \n",
      " 아이템 셋. \n",
      " 아이템 넷. \n",
      " 아이템 다섯. \n",
      " 아이템 여섯.\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 모든 <div> 태그의 내용을 찾아서 이어 붙여서 출력한다.\n",
    "x=soup.find_all('div')    #모든 p태그 가져오기    #x는 리스트성격\n",
    "n = len(x)              #길이로 x의 원소개수 확인\n",
    "result = ''             #빈 문자열 만들어 원소 하나하나 가져옴     # 초기화.\n",
    "\n",
    "#x[i]태그객체를 가져와 text속성가져옴\n",
    "for i in range(n):\n",
    "    result += x[i].text.strip() + '\\n\\n'    #문자열 메서드 strip(왼쪽 오른쪽 스페이스 떨궈줌)\n",
    "                                            #\\n\\n(라인 체인지), +(두개 연결)\n",
    "\n",
    "# 출력.\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3 BeautifulSoup4 라이브러리로 parsing을 한다: ol태그"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      " 아이템 하나. \n",
      " 아이템 둘. \n",
      " 아이템 셋. \n",
      " 아이템 넷. \n",
      " 아이템 다섯. \n",
      " 아이템 여섯. \n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 첫 번째 <ol> 태그를 찾아서 출력해 본다.\n",
    "x=soup.find('ol')     \n",
    "print(x.text)      # 첫 ol태그의 text 속성    #내용 보여줌, 하위태그 포함, 문자열 타입"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. find, find_all 메서드와 CSS 셀렉터를 조합해 특정 태그에 접근해 본다:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 특정 클래스 가져오기"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<h1 class=\"myClass1\"> 헤더 1.1 </h1>\n",
      "<h2 class=\"myClass1\"> 헤더 1.1 </h2>\n",
      "<p class=\"myClass1\"> Paragraph 1. </p>\n",
      "<p class=\"myClass1\"> Paragraph 4. </p>\n",
      "<li class=\"myClass1\"> 아이템 하나. </li>\n",
      "<li class=\"myClass1\"> 아이템 넷. </li>\n"
     ]
    }
   ],
   "source": [
    "res = soup.find_all(class_='myClass1')   #myClass1이라는 클래스를 갖는 태그들만 가져온다\n",
    "for x in res:\n",
    "    print(x)                             #클래스는 같지만 서로다른 태그들을 가져온게 보임"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 아이템 넷. \n"
     ]
    }
   ],
   "source": [
    "print(x.text)                       "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 헤더 1.2 \n",
      " 헤더 1.2 \n",
      " Paragraph 2. \n",
      " Paragraph 5. \n",
      " 아이템 둘. \n",
      " 아이템 다섯. \n"
     ]
    }
   ],
   "source": [
    "res = soup.find_all(class_='myClass2')     \n",
    "for x in res:\n",
    "    print(x.text)   #지저분한 태그떼고 내용들만 보여줌"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 특정 태그와 클래스 조합 가져오기"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Paragraph 2. \n",
      " Paragraph 5. \n"
     ]
    }
   ],
   "source": [
    "res = soup.find_all('p',class_='myClass2')   #p태그면서 myClass2인거만\n",
    "for x in res:\n",
    "    print(x.text)                            #p태그이면서 myClass2인 결과는 2가지"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<p class=\"myClass2\"> Paragraph 5. </p>\n"
     ]
    }
   ],
   "source": [
    "print(x) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 아이템 셋. \n",
      " 아이템 여섯. \n"
     ]
    }
   ],
   "source": [
    "res = soup.find_all('li',class_='myClass3')   #li태그면서 myClass3인거만\n",
    "for x in res:    \n",
    "    print(x.text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<li class=\"myClass3\"> 아이템 여섯. </li>\n"
     ]
    }
   ],
   "source": [
    "print(x) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 특정 ID 가져오기"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Paragraph 2. \n"
     ]
    }
   ],
   "source": [
    "res = soup.find(id='myID1')\n",
    "print(res.text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " 아이템 셋. \n"
     ]
    }
   ],
   "source": [
    "res = soup.find(id='myID2')\n",
    "print(res.text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}