Skip to content

Commit 2315b0c

Browse files
committed
更新了爬虫第2天文档
1 parent e86dece commit 2315b0c

File tree

3 files changed

+125
-44
lines changed

3 files changed

+125
-44
lines changed

Day66-75/02.数据采集和解析.md

+65
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,73 @@
11
## 数据采集和解析
22

3+
通过上一个章节,我们已经了解到了开发一个爬虫需要做的工作以及一些常见的问题,至此我们可以对爬虫开发需要做的工作以及相关的技术做一个简单的汇总,可能有些库我们之前并没有使用过,不过别担心,这些内容我们都会讲到的。
4+
5+
1. 下载数据 - urllib / requests / aiohttp。
6+
2. 解析数据 - re / lxml / beautifulsoup4(bs4)/ pyquery。
7+
3. 持久化 - pymysql / redis / sqlalchemy / pymongo。
8+
4. 调度器 - 进程 / 线程 / 协程。
9+
310
### HTML页面分析
411

12+
```HTML
13+
<!DOCTYPE html>
14+
<html lang="en">
15+
<head>
16+
<meta charset="UTF-8">
17+
<title>首页</title>
18+
</head>
19+
<body>
20+
<h1>Hello, world!</h1>
21+
<p>这是一个神奇的网站!</p>
22+
<hr>
23+
<div>
24+
<h2>这是一个例子程序</h2>
25+
<p>静夜思</p>
26+
<p class="foo">床前明月光</p>
27+
<p id="bar">疑似地上霜</p>
28+
<p class="foo">举头望明月</p>
29+
<div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
30+
</div>
31+
<a class="foo" href="http://www.qq.com">腾讯网</a>
32+
<img src="./img/pretty-girl.png" alt="美女">
33+
<img src="./img/hellokitty.png" alt="凯蒂猫">
34+
<img src="/static/img/pretty-girl.png" alt="美女">
35+
<table>
36+
<tr>
37+
<th>姓名</th>
38+
<th>上场时间</th>
39+
<th>得分</th>
40+
<th>篮板</th>
41+
<th>助攻</th>
42+
</tr>
43+
</table>
44+
</body>
45+
</html>
46+
```
47+
48+
如果你对上面的代码并不感到陌生,那么你一定知道HTML页面通常由三部分构成,分别是:用来承载内容的Tag(标签)、负责渲染页面的CSS(层叠样式表)以及控制交互式行为的JavaScript。通常,我们可以在浏览器的右键菜单中通过“查看网页源代码”的方式获取网页的代码并了解页面的结构;当然,我们也可以通过浏览器提供的开发人员工具来了解网页更多的信息。
49+
50+
#### 使用requests获取页面
51+
52+
1. GET请求和POST请求。
53+
2. URL参数和请求头。
54+
3. 复杂的POST请求(文件上传)。
55+
4. 操作Cookie。
56+
557
### 三种采集方式
658

59+
#### 三种采集方式的比较
60+
61+
| 抓取方法 | 速度 | 使用难度 | 备注 |
62+
| ---------- | --------------------- | -------- | ------------------------------------------ |
63+
| 正则表达式 || 困难 | 常用正则表达式<br>在线正则表达式测试 |
64+
| lxml || 一般 | 需要安装C语言依赖库<br>唯一支持XML的解析器 |
65+
| Beautiful | 快/慢(取决于解析器) | 简单 | |
66+
67+
> 说明:Beautiful的解析器包括:Python标准库(html.parser)、lxml的HTML解析器、lxml的XML解析器和html5lib。
68+
69+
#### BeautifulSoup的使用
770

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

Day66-75/code/example01.py

+26-17
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from pymysql import Error
99

1010

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

2223

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

3436

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

3942

40-
def start_crawl(seed_url, match_pattern):
43+
# 开始执行爬虫程序并对指定的数据进行持久化操作
44+
def start_crawl(seed_url, match_pattern, *, max_depth=-1):
4145
conn = pymysql.connect(host='localhost', port=3306,
4246
database='crawler', user='root',
4347
password='123456', charset='utf8')
4448
try:
4549
with conn.cursor() as cursor:
4650
url_list = [seed_url]
51+
visited_url_list = {seed_url: 0}
4752
while url_list:
4853
current_url = url_list.pop(0)
49-
page_html = get_page_html(current_url, charsets=('utf-8', 'gbk', 'gb2312'))
50-
links_list = get_matched_parts(page_html, match_pattern)
51-
url_list += links_list
52-
param_list = []
53-
for link in links_list:
54-
page_html = get_page_html(link, charsets=('utf-8', 'gbk', 'gb2312'))
55-
headings = get_matched_parts(page_html, r'<h1>(.*)<span')
56-
if headings:
57-
param_list.append((headings[0], link))
58-
cursor.executemany('insert into tb_result values (default, %s, %s)',
59-
param_list)
60-
conn.commit()
54+
depth = visited_url_list[current_url]
55+
if depth != max_depth:
56+
page_html = get_page_html(current_url, charsets=('utf-8', 'gbk', 'gb2312'))
57+
links_list = get_matched_parts(page_html, match_pattern)
58+
param_list = []
59+
for link in links_list:
60+
if link not in visited_url_list:
61+
visited_url_list[link] = depth + 1
62+
page_html = get_page_html(link, charsets=('utf-8', 'gbk', 'gb2312'))
63+
headings = get_matched_parts(page_html, r'<h1>(.*)<span')
64+
if headings:
65+
param_list.append((headings[0], link))
66+
cursor.executemany('insert into tb_result values (default, %s, %s)',
67+
param_list)
68+
conn.commit()
6169
except Error:
6270
pass
6371
# logging.error('SQL:', error)
@@ -67,8 +75,9 @@ def start_crawl(seed_url, match_pattern):
6775

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

7382

7483
if __name__ == '__main__':

Day66-75/code/example02.py

+34-27
Original file line numberDiff line numberDiff line change
@@ -7,38 +7,45 @@ def main():
77
html = """
88
<!DOCTYPE html>
99
<html lang="en">
10-
<head>
11-
<meta charset="UTF-8">
12-
<title>首页</title>
13-
</head>
14-
<body>
15-
<h1>Hello, world!</h1>
16-
<p>Good!!!</p>
17-
<hr>
18-
<div>
19-
<h2>这是一个例子程序</h2>
20-
<p>静夜思</p>
21-
<p class="foo">床前明月光</p>
22-
<p id="bar">疑似地上霜</p>
23-
<p class="foo">举头望明月</p>
24-
<div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
25-
</div>
26-
<a class="foo" href="http://www.qq.com">腾讯网</a>
27-
<img src="./img/pretty-girl.png" alt="美女">
28-
<img src="./img/hellokitty.png" alt="凯蒂猫">
29-
<img src="./static/img/pretty-girl.png" alt="美女">
30-
<goup>Hello, Goup!</goup>
31-
</body>
10+
<head>
11+
<meta charset="UTF-8">
12+
<title>首页</title>
13+
</head>
14+
<body>
15+
<h1>Hello, world!</h1>
16+
<p>这是一个神奇的网站!</p>
17+
<hr>
18+
<div>
19+
<h2>这是一个例子程序</h2>
20+
<p>静夜思</p>
21+
<p class="foo">床前明月光</p>
22+
<p id="bar">疑似地上霜</p>
23+
<p class="foo">举头望明月</p>
24+
<div><a href="http://www.baidu.com"><p>低头思故乡</p></a></div>
25+
</div>
26+
<a class="foo" href="http://www.qq.com">腾讯网</a>
27+
<img src="./img/pretty-girl.png" alt="美女">
28+
<img src="./img/hellokitty.png" alt="凯蒂猫">
29+
<img src="/static/img/pretty-girl.png" alt="美女">
30+
<table>
31+
<tr>
32+
<th>姓名</th>
33+
<th>上场时间</th>
34+
<th>得分</th>
35+
<th>篮板</th>
36+
<th>助攻</th>
37+
</tr>
38+
</table>
39+
</body>
3240
</html>
3341
"""
34-
# resp = requests.get('http://sports.sohu.com/nba_a.shtml')
35-
# html = resp.content.decode('gbk')
3642
soup = BeautifulSoup(html, 'lxml')
43+
# JavaScript - document.title
3744
print(soup.title)
38-
# JavaScript: document.body.h1
39-
# JavaScript: document.forms[0]
45+
# JavaScript - document.body.h1
4046
print(soup.body.h1)
41-
print(soup.find_all(re.compile(r'p$')))
47+
print(soup.find_all(re.compile(r'^h')))
48+
print(soup.find_all(re.compile(r'r$')))
4249
print(soup.find_all('img', {'src': re.compile(r'\./img/\w+.png')}))
4350
print(soup.find_all(lambda x: len(x.attrs) == 2))
4451
print(soup.find_all('p', {'class': 'foo'}))

0 commit comments

Comments
 (0)