爬虫 - BeautifulSoup

bs4

Beautiful Soup 是一个使从 web 页面获取信息变得容易的库。它位于 HTML 或 XML 解析器之上,提供了迭代、搜索和修改解析树的 python 风格。

需要将 pip 源设置为国内源:阿里源、豆瓣源、网易源等

  • Windows

    1. 打开文件资源管理
    2. 地址栏上面输入 %appdata%
    3. 在这里面新建一个文件夹 pip
    4. pip 文件夹里面新建一个文件叫做 pip.ini, 内容写如下即可
      1
      2
      3
      4
      [global]
      timeout = 6000
      index-url = https://mirrors.aliyun.com/pypi/simple/
      trusted-host = mirrors.aliyun.com
  • Linux

    1. cd ~
    2. mkdir ~/.pip
    3. vi ~/.pip/pip.conf
    4. 编辑内容,和 windows 一模一样

安装

1
pip install bs4
1
pip install lxml

bs4 在使用时候需要的一个第三方库

简单使用

  • 导入包

    1
    from bs4 import BeautifulSoup
  • 使用方式

    可以将一个 html 文档,转化为指定的对象,然后通过对象的方法或者属性去查找指定的内容

    1. 转化本地文件
      1
      soup = BeautifulSoup(open('本地文件'), 'lxml')
    2. 转化网络文件
      1
      soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
  1. 根据标签名查找

    1
    soup.a   # 只能找到第一个符合要求的标签
  2. 获取属性

    1
    2
    3
    soup.a.attrs           # 获取所有的属性和值,返回一个字典
    soup.a.attrs['href'] # 获取href属性
    soup.a['href'] # 也可简写为这种形式
  3. 获取内容

    1
    2
    3
    soup.a.string
    soup.a.text
    soup.a.get_text()

    如果标签还有标签,那么 string 获取到的结果为 None,而其它两个,可以获取文本内容

  4. find

    1
    2
    3
    4
    5
    soup.find('a')   # 找到第一个符合要求的a
    soup.find('a', title="xxx")
    soup.find('a', alt="xxx")
    soup.find('a', class_="xxx")
    soup.find('a', id="xxx")

    find 方法不仅 soup 可以调用,普通的 div 对象也能调用,会去指定的 div 里面去查找符合要求的节点
    find 找到的都是第一个符合要求的标签

  5. find_all

    1
    2
    3
    soup.find_all('a')           # 查找所有的a
    soup.find_all(['a', 'b']) # 查找所有的a和b
    soup.find_all('a', limit=2) # 查找前两个a
  6. select

    • 根据选择器选择指定的内容
    • 常见的选择器:标签选择器、类选择器、id 选择器、组合选择器、层级选择器、伪类选择器、属性选择器
      1
      2
      3
      4
      5
      6
      7
      a  
      .dudu
      #lala
      a, .dudu, #lala, .meme
      div .dudu #lala .meme .xixi # 下面好多级
      div > p > a > .lala # 只能是下面一级
      input[name='lala']

      select 选择器返回永远是列表,需要通过下标提取指定的对象,然后获取属性和节点
      该方法也可以通过普通对象调用,找到都是这个对象下面符合要求的所有节点。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from bs4 import BeautifulSoup


def main():
# 生成对象
soup = BeautifulSoup(open('soup_text.html', encoding="utf8"), 'lxml')
# print(soup)
# print(type(soup)) # <class 'bs4.BeautifulSoup'>
# print(soup.a)
# print(type(soup.a)) # <class 'bs4.element.Tag'>
# print(soup.div)
# print(type(soup.div)) # <class 'bs4.element.Tag'>
# print(soup.a['href'])
# print(soup.a['title'])
# print(soup.a['target'])
# print(soup.a.attrs)
# print(soup.a.attrs['title'])

# print(soup.div.text)
# print('*********************************')
# print(soup.div.string)
# print('*********************************')
# print(soup.div.get_text())

# print(soup.find('a'))
# print(soup.find('a', title='qin'))
# print(soup.find('a', alt='qi'))
# print(soup.find('a', class_="du"))
# print(soup.find('a', id="feng"))

# div = soup.find('div', class_="tang")
# print(div.find('a', class_='du'))

# print(soup.find_all('a', class_='du'))
# print(soup.find_all(['a', 'b']))
# print(soup.find_all('a', limit=2))

# print(soup.select('.tang > ul > li > a')[2])
# print(soup.select('#feng')[0]['href'])
div = soup.find('div', class_='tang')
print(div.select('.du'))


if __name__ == '__main__':
main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>测试bs4</title>
</head>
<body>
<div>
<p>百里守约</p>
</div>
<div class="song">
<p>李清照</p>
<p>王安石</p>
<p>苏轼</p>
<p>柳宗元</p>
<a href="http://www.song.com/" title="赵匡胤" target="_self">宋朝是最强大的王朝,不是军队的强大,而是经济很强大,国民都很有钱</a>
<a href="" class="du">总为浮云能蔽日,长安不见使人愁</a>
<img src="http://www.baidu.com/meinv.jpg" alt="">
</div>
<div class="tang">
<ul>
<li><a href="http://www.baidu.com" title="qing">清明时节雨纷纷,路上行人欲断魂,借问酒家何处有,牧童遥指杏花村</a></li>
<li><a href="http://www.163.com" title="qin">秦时明月汉时关,万里长征人未还,但使龙城飞将在,不教胡马度阴山</a></li>
<li><a href="http://www.126.com" alt="qi">岐王宅里寻常见,崔九堂前几度闻,正是江南好风景,落花时节又逢君</a></li>
<li><a href="http://www.sina.com" class="du">杜甫</a></li>
<li><a href="http://www.dudu.com" class="du">杜牧</a></li>
<li><b>杜小月</b></li>
<li><i>度蜜月</i></li>
<li><a href="http://www.haha.com" id="feng">凤凰台上凤凰游,凤去台空江自流,吴宫花草埋幽径,晋代衣冠成古丘</a></li>
</ul>
</div>
</body>
</html>

bs4 实例

示例 1:爬取三国演义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
import time


def handle_request(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
request = urllib.request.Request(url, headers=headers)
return request


# 下载章节内容函数
def download_text(href):
# 构建请求对象
request = handle_request(href)
# 获取网页内容
content = urllib.request.urlopen(request).read().decode()
# print(content)
# exit()
soup = BeautifulSoup(content, 'lxml')
# 获取内容
odiv = soup.find('div', class_="chapter_content")
return odiv.text


def parse_content(content):
# 生成一个对象
soup = BeautifulSoup(content, 'lxml')
# <div class="book-mulu">(.*?)</div>
# <li><a href="(/book/sanguoyanyi/\d+\.html)">(.*?)</a></li>
a_list = soup.select('.book-mulu > ul > li > a')
# print(a_list)
# print(len(a_list))
# 遍历这个列表,获取title和href,然后获取内容
for element in a_list:
# 根据对象获取内容
title = element.text
# 根据对象获取属性
href = 'http://www.shicimingju.com' + element['href']
# 根据href获取内容的函数
print('开始下载---%s' % title)
text = download_text(href)
print('结束下载---%s' % title)
string = title + '\n' + text + '\n'
# 将标题和内容写入到文件中
with open('三国演义.txt', 'a', encoding='utf8') as fp:
fp.write(string)
time.sleep(2)


def main():
url = 'http://www.shicimingju.com/book/sanguoyanyi.html'
# 构建请求对象
request = handle_request(url)
# 发送请求对象,获取响应
content = urllib.request.urlopen(request).read().decode()
# 解析内容
parse_content(content)


if __name__ == '__main__':
main()

示例 2:爬取智联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import urllib.request
import urllib.parse
from bs4 import BeautifulSoup
import json
import time


# http://sou.zhaopin.com/jobs/searchresult.ashx

class ZhiLianSpider(object):
# url中不变的内容,要和参数进行拼接组成完整的url
url = 'http://sou.zhaopin.com/jobs/searchresult.ashx?'

def __init__(self, jl, kw, start_page, end_page):
# 将上面的参数都保存为自己的成员属性
self.jl = jl
self.kw = kw
self.start_page = start_page
self.end_page = end_page
# 定义一个空列表,用来存放所有的工作信息
self.items = []

# 根据page拼接指定的url,然后生成请求对象
def handle_request(self, page):
data = {
'jl': self.jl,
'kw': self.kw,
'p': page
}
url_now = self.url + urllib.parse.urlencode(data)
# 构建请求对象
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}
request = urllib.request.Request(url=url_now, headers=headers)
return request

# 解析内容函数
def parse_content(self, content):
# 生成对象
soup = BeautifulSoup(content, 'lxml')
# 思路:先找到所有的table,因为一个工作岗位就是一个table,遍历这个table的列表,然后通过table对象的select、find方法去找每一条记录的具体信息
table_list = soup.select('#newlist_list_content_table > table')[1:]
# 遍历这个table_list,依次获取每一个数据
for table in table_list:
# 获取职位名称
zwmc = table.select('.zwmc > div > a')[0].text
# print(zwmc)
# 获取公司名称
gsmc = table.select('.gsmc > a')[0].text
# 获取职位月薪
zwyx = table.select('.zwyx')[0].text
# 获取工作地点
gzdd = table.select('.gzdd')[0].text
# 获取发布时间
gxsj = table.select('.gxsj > span')[0].text
# 存放到字典中
item = {
'职位名称': zwmc,
'公司名称': gsmc,
'职位月薪': zwyx,
'工作地点': gzdd,
'更新时间': gxsj,
}
# 再存放到列表中
self.items.append(item)

# 爬取程序
def run(self):
# 搞个循环,循环爬取每一页数据
for page in range(self.start_page, self.end_page + 1):
print('开始爬取第%s页' % page)
request = self.handle_request(page)
# 发送请求,获取内容
content = urllib.request.urlopen(request).read().decode()
# 解析内容
self.parse_content(content)
print('结束爬取第%s页' % page)
time.sleep(2)

# 将列表数据保存到文件中
string = json.dumps(self.items, ensure_ascii=False)
with open('zhilian.txt', 'w', encoding='utf8') as fp:
fp.write(string)


def main():
jl = input('请输入工作地点:')
kw = input('请输入工作关键字:')
start_page = int(input('请输入起始页码:'))
end_page = int(input('请输入结束页码:'))

# 创建对象,启动爬取程序
spider = ZhiLianSpider(jl, kw, start_page, end_page)
spider.run()


if __name__ == '__main__':
main()
------------- 本文结束 感谢您的阅读 -------------
正在加载今日诗词....