diff --git a/.ipynb_checkpoints/Chapter04_FirstWebScraper-checkpoint.ipynb b/.ipynb_checkpoints/Chapter04_FirstWebScraper-checkpoint.ipynb new file mode 100644 index 0000000..13814b1 --- /dev/null +++ b/.ipynb_checkpoints/Chapter04_FirstWebScraper-checkpoint.ipynb @@ -0,0 +1,181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Writing Your First Web Scraper" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "b'\\n\\nA Useful Page\\n\\n\\n

An Interesting Title

\\n
\\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\\n
\\n\\n\\n'\n" + ] + } + ], + "source": [ + "from urllib.request import urlopen\n", + "\n", + "html = urlopen('http://pythonscraping.com/pages/page1.html')\n", + "print(html.read())" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "

An Interesting Title

\n" + ] + } + ], + "source": [ + "from urllib.request import urlopen\n", + "from bs4 import BeautifulSoup\n", + "\n", + "html = urlopen('http://www.pythonscraping.com/pages/page1.html')\n", + "bs = BeautifulSoup(html.read(), 'html.parser')\n", + "print(bs.h1)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from urllib.request import urlopen\n", + "from bs4 import BeautifulSoup\n", + "\n", + "html = urlopen('https://en.wikipedia.org/wiki/Iron_Gwazi')\n", + "bs = BeautifulSoup(html.read(), 'html.parser')\n", + "# 'class':['mw-file-description']\n", + "#bs.find_all(attrs={'class': ['mw-ui-icon-wikimedia-listBullet', 'vector-icon']})\n", + "\n", + "bs.find_all(_class='mw-ui-icon-wikimedia-listBullet')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The server could not be found!\n" + ] + } + ], + "source": [ + "from urllib.request import urlopen\n", + "from urllib.error import HTTPError\n", + "from urllib.error import URLError\n", + "\n", + "try:\n", + " html = urlopen(\"https://pythonscrapingthisurldoesnotexist.com\")\n", + "except HTTPError as e:\n", + " print(\"The server returned an HTTP error\")\n", + "except URLError as e:\n", + " print(\"The server could not be found!\")\n", + "else:\n", + " print(html.read())" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "

An Interesting Title

\n" + ] + } + ], + "source": [ + "from urllib.request import urlopen\n", + "from urllib.error import HTTPError\n", + "from bs4 import BeautifulSoup\n", + "\n", + "\n", + "def getTitle(url):\n", + " try:\n", + " html = urlopen(url)\n", + " except HTTPError as e:\n", + " return None\n", + " try:\n", + " bsObj = BeautifulSoup(html.read(), \"lxml\")\n", + " title = bsObj.body.h1\n", + " except AttributeError as e:\n", + " return None\n", + " return title\n", + "\n", + "\n", + "title = getTitle(\"http://www.pythonscraping.com/pages/page1.html\")\n", + "if title is None:\n", + " print(\"Title could not be found\")\n", + "else:\n", + " print(title)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Chapter04_FirstWebScraper.ipynb b/Chapter04_FirstWebScraper.ipynb index 58850e8..13814b1 100644 --- a/Chapter04_FirstWebScraper.ipynb +++ b/Chapter04_FirstWebScraper.ipynb @@ -29,7 +29,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -51,7 +51,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -60,7 +60,7 @@ "[]" ] }, - "execution_count": 34, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -79,7 +79,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -107,7 +107,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -138,7 +138,7 @@ "\n", "\n", "title = getTitle(\"http://www.pythonscraping.com/pages/page1.html\")\n", - "if title == None:\n", + "if title is None:\n", " print(\"Title could not be found\")\n", "else:\n", " print(title)" @@ -148,7 +148,10 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": true + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } }, "outputs": [], "source": [] @@ -170,9 +173,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.12" + "version": "3.12.2" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/README.md b/README.md index fc126cd..3229abc 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,35 @@ -# Web Scraping with Python Code Samples +# 파이썬으로 웹 크롤러 만들기(3판) -These code samples are for the book Web Scraping with Python 2nd Edition +『파이썬으로 웹 크롤러 만들기(3판)』(한빛미디어, 2025) 예제 코드 저장소입니다. +이 저장소의 코드는 원서의 저자가 제공하는 코드 중 실행 오류가 발생하거나 오탈자가 있는 부분을 수정한 것입니다. -If you're looking for the first edition code files, they can be found in the v1 directory. +원서의 저자가 제공하는 [코드](https://github.com/REMitchell/python-scraping)는 여기에서 확인할 수 있습니다. -Most code for the second edition is contained in Jupyter notebooks. Although these files can be viewed directly in your browser in Github, some formatting changes and oddities may occur. I recommend that you clone the repository, install Jupyter, and view them locally for the best experience. +## 이 책에 대하여 +오늘날 데이터가 넘쳐나는 웹에서 웹 크롤러로 할 수 있는 일은 무궁무진합니다. 이 마법을 위한 준비물은 약간의 파이썬 프로그래밍 능력 하나뿐, 나머지는 이 책에 모두 담겨 있습니다. 이 책을 활용하면 웹 크롤링을 이용해 업무를 자동화하고, 복잡한 웹 콘텐츠를 처리하는 통찰력을 얻게 될 것입니다. 새롭게 3판으로 개정된 이 책은 전반적인 코드를 최신화하고 실무에서 활용할 수 있는 예제를 추가했습니다. 또한 브라우저 자동화를 위한 셀레니움, 정확한 데이터 추출을 위한 XPath도 함께 다룹니다. 복잡한 웹 세상에서 효율적으로 데이터를 수집하고 싶은, ‘일상의 데이터 분석가’를 꿈꾸는 모두에게 이 책은 가장 정확한 나침반이 되어 줄 것입니다. -The web changes, libraries update, and make mistakes and typos more frequently than I'd like to admit! If you think you've spotted an error, please feel free to make a pull request against this repository. +## 목차 + +PART 1 웹 스크레이퍼 제작 +CHAPTER 1 인터넷 작동 원리 +CHAPTER 2 웹 스크레이핑의 합법성과 윤리 +CHAPTER 3 웹 스크레이핑 활용 분야 +CHAPTER 4 첫 번째 웹 스크레이퍼 +CHAPTER 5 고급 HTML 분석 +CHAPTER 6 크롤링 시작하기 +CHAPTER 7 웹 크롤링 모델 +CHAPTER 8 스크레이피 +CHAPTER 9 데이터 저장 + +PART 2 고급 스크레이핑 +CHAPTER 10 문서 읽기 +CHAPTER 11 지저분한 데이터 다루기 +CHAPTER 12 자연어 읽고 쓰기 +CHAPTER 13 폼과 로그인 뚫기 +CHAPTER 14 자바스크립트 스크레이핑 +CHAPTER 15 API를 통한 크롤링 +CHAPTER 16 이미지 처리와 텍스트 인식 +CHAPTER 17 스크레이핑 함정 피하기 +CHAPTER 18 스크레이퍼로 웹사이트 테스트하기 +CHAPTER 19 병렬 웹 스크레이핑 +CHAPTER 20 웹 스크레이핑 프록시