Skip to content

Commit

Permalink
更新了爬虫第2天文档
Browse files Browse the repository at this point in the history
  • Loading branch information
jackfrued committed May 28, 2018
1 parent e86dece commit 2315b0c
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 44 deletions.
65 changes: 65 additions & 0 deletions Day66-75/02.数据采集和解析.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,73 @@
## 数据采集和解析

通过上一个章节,我们已经了解到了开发一个爬虫需要做的工作以及一些常见的问题,至此我们可以对爬虫开发需要做的工作以及相关的技术做一个简单的汇总,可能有些库我们之前并没有使用过,不过别担心,这些内容我们都会讲到的。

1. 下载数据 - urllib / requests / aiohttp。
2. 解析数据 - re / lxml / beautifulsoup4(bs4)/ pyquery。
3. 持久化 - pymysql / redis / sqlalchemy / pymongo。
4. 调度器 - 进程 / 线程 / 协程。

### HTML页面分析

```HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>Hello, world!</h1>
<p>这是一个神奇的网站!</p>
<hr>
<div>
<h2>这是一个例子程序</h2>
<p>静夜思</p>
<p class="foo">床前明月光</p>
<p id="bar">疑似地上霜</p>
<p class="foo">举头望明月</p>
<div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
</div>
<a class="foo" href="http://www.qq.com">腾讯网</a>
<img src="./img/pretty-girl.png" alt="美女">
<img src="./img/hellokitty.png" alt="凯蒂猫">
<img src="/static/img/pretty-girl.png" alt="美女">
<table>
<tr>
<th>姓名</th>
<th>上场时间</th>
<th>得分</th>
<th>篮板</th>
<th>助攻</th>
</tr>
</table>
</body>
</html>
```

如果你对上面的代码并不感到陌生,那么你一定知道HTML页面通常由三部分构成,分别是:用来承载内容的Tag(标签)、负责渲染页面的CSS(层叠样式表)以及控制交互式行为的JavaScript。通常,我们可以在浏览器的右键菜单中通过“查看网页源代码”的方式获取网页的代码并了解页面的结构;当然,我们也可以通过浏览器提供的开发人员工具来了解网页更多的信息。

#### 使用requests获取页面

1. GET请求和POST请求。
2. URL参数和请求头。
3. 复杂的POST请求(文件上传)。
4. 操作Cookie。

### 三种采集方式

#### 三种采集方式的比较

| 抓取方法 | 速度 | 使用难度 | 备注 |
| ---------- | --------------------- | -------- | ------------------------------------------ |
| 正则表达式 || 困难 | 常用正则表达式<br>在线正则表达式测试 |
| lxml || 一般 | 需要安装C语言依赖库<br>唯一支持XML的解析器 |
| Beautiful | 快/慢(取决于解析器) | 简单 | |

> 说明:Beautiful的解析器包括:Python标准库(html.parser)、lxml的HTML解析器、lxml的XML解析器和html5lib。
#### BeautifulSoup的使用

1. 遍历文档树。
2. 五种过滤器:字符串、正则表达式、列表、True、方法。

43 changes: 26 additions & 17 deletions Day66-75/code/example01.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from pymysql import Error


def decode_page(page_bytes, charsets=('utf-8', )):
# 通过指定的字符集对页面进行解码(不是每个网站都将字符集设置为utf-8)
def decode_page(page_bytes, charsets=('utf-8',)):
page_html = None
for charset in charsets:
try:
Expand All @@ -20,7 +21,8 @@ def decode_page(page_bytes, charsets=('utf-8', )):
return page_html


def get_page_html(seed_url, *, retry_times=3, charsets=('utf-8', )):
# 获取页面的HTML代码(通过递归实现指定次数的重试操作)
def get_page_html(seed_url, *, retry_times=3, charsets=('utf-8',)):
page_html = None
try:
page_html = decode_page(urlopen(seed_url).read(), charsets)
Expand All @@ -32,32 +34,38 @@ def get_page_html(seed_url, *, retry_times=3, charsets=('utf-8', )):
return page_html


# 从页面中提取需要的部分(通常是链接也可以通过正则表达式进行指定)
def get_matched_parts(page_html, pattern_str, pattern_ignore_case=re.I):
pattern_regex = re.compile(pattern_str, pattern_ignore_case)
return pattern_regex.findall(page_html) if page_html else []


def start_crawl(seed_url, match_pattern):
# 开始执行爬虫程序并对指定的数据进行持久化操作
def start_crawl(seed_url, match_pattern, *, max_depth=-1):
conn = pymysql.connect(host='localhost', port=3306,
database='crawler', user='root',
password='123456', charset='utf8')
try:
with conn.cursor() as cursor:
url_list = [seed_url]
visited_url_list = {seed_url: 0}
while url_list:
current_url = url_list.pop(0)
page_html = get_page_html(current_url, charsets=('utf-8', 'gbk', 'gb2312'))
links_list = get_matched_parts(page_html, match_pattern)
url_list += links_list
param_list = []
for link in links_list:
page_html = get_page_html(link, charsets=('utf-8', 'gbk', 'gb2312'))
headings = get_matched_parts(page_html, r'<h1>(.*)<span')
if headings:
param_list.append((headings[0], link))
cursor.executemany('insert into tb_result values (default, %s, %s)',
param_list)
conn.commit()
depth = visited_url_list[current_url]
if depth != max_depth:
page_html = get_page_html(current_url, charsets=('utf-8', 'gbk', 'gb2312'))
links_list = get_matched_parts(page_html, match_pattern)
param_list = []
for link in links_list:
if link not in visited_url_list:
visited_url_list[link] = depth + 1
page_html = get_page_html(link, charsets=('utf-8', 'gbk', 'gb2312'))
headings = get_matched_parts(page_html, r'<h1>(.*)<span')
if headings:
param_list.append((headings[0], link))
cursor.executemany('insert into tb_result values (default, %s, %s)',
param_list)
conn.commit()
except Error:
pass
# logging.error('SQL:', error)
Expand All @@ -67,8 +75,9 @@ def start_crawl(seed_url, match_pattern):

def main():
ssl._create_default_https_context = ssl._create_unverified_context
start_crawl('http://sports.sohu.com/nba_a.shtml',
r'<a[^>]+test=a\s[^>]*href=["\'](.*?)["\']')
start_crawl('http://sports.sohu.com/nba_a.shtml',
r'<a[^>]+test=a\s[^>]*href=["\'](.*?)["\']',
max_depth=2)


if __name__ == '__main__':
Expand Down
61 changes: 34 additions & 27 deletions Day66-75/code/example02.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,45 @@ def main():
html = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>Hello, world!</h1>
<p>Good!!!</p>
<hr>
<div>
<h2>这是一个例子程序</h2>
<p>静夜思</p>
<p class="foo">床前明月光</p>
<p id="bar">疑似地上霜</p>
<p class="foo">举头望明月</p>
<div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
</div>
<a class="foo" href="http://www.qq.com">腾讯网</a>
<img src="./img/pretty-girl.png" alt="美女">
<img src="./img/hellokitty.png" alt="凯蒂猫">
<img src="./static/img/pretty-girl.png" alt="美女">
<goup>Hello, Goup!</goup>
</body>
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>Hello, world!</h1>
<p>这是一个神奇的网站!</p>
<hr>
<div>
<h2>这是一个例子程序</h2>
<p>静夜思</p>
<p class="foo">床前明月光</p>
<p id="bar">疑似地上霜</p>
<p class="foo">举头望明月</p>
<div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
</div>
<a class="foo" href="http://www.qq.com">腾讯网</a>
<img src="./img/pretty-girl.png" alt="美女">
<img src="./img/hellokitty.png" alt="凯蒂猫">
<img src="/static/img/pretty-girl.png" alt="美女">
<table>
<tr>
<th>姓名</th>
<th>上场时间</th>
<th>得分</th>
<th>篮板</th>
<th>助攻</th>
</tr>
</table>
</body>
</html>
"""
# resp = requests.get('http://sports.sohu.com/nba_a.shtml')
# html = resp.content.decode('gbk')
soup = BeautifulSoup(html, 'lxml')
# JavaScript - document.title
print(soup.title)
# JavaScript: document.body.h1
# JavaScript: document.forms[0]
# JavaScript - document.body.h1
print(soup.body.h1)
print(soup.find_all(re.compile(r'p$')))
print(soup.find_all(re.compile(r'^h')))
print(soup.find_all(re.compile(r'r$')))
print(soup.find_all('img', {'src': re.compile(r'\./img/\w+.png')}))
print(soup.find_all(lambda x: len(x.attrs) == 2))
print(soup.find_all('p', {'class': 'foo'}))
Expand Down

0 comments on commit 2315b0c

Please sign in to comment.