beautifulsoup&pyquery
beautifulsoup
和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。
lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。
简单说 : beasoup的作用是从HTML中提取数据,会载入整个HTML,DOM 比lxml解析器效率低
安装: pip3 install beautifulsoup4
eg : 以腾讯招聘为例
'''
https://hr.tencent.com/position.php?
https://hr.tencent.com/position.php?&start=10
'''
from bs4 import BeautifulSoup
import requests
import mysql.connector as c
def tengxunJob(url):
# 构建下一页偏移量
# next_offset = offset + 10
# 继续发起请求,解析数据
# tengxunJob(next_offset)
# 这种根据偏移量构建下一页的方式并不好,如果有下一页可以提取该标签的href属性
html = load_data(full_url)
next_url = parse_page_data(html)
if 'javascript:;
' != next_url:
next_url = 'https://hr.tencent.com/' + next_url
tengxunJob(next_url)
def load_data(url):
'''
发起请求,获取职位列表页HTML
:param url:
:return:
'''
req_header = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0;
WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 '
}
response = requests.get(url,headers=req_header)
if response.status_code == 200:
return response.text
def parse_page_data(html):
'''
解析分页的HTML源码数据
:return:
'''
'''
features = None : 指明bs解析器
lxml : 使用lxml下的HTML解析器
html.parser : 是Python自带的一个解析器模块
'''
html_bs = BeautifulSoup(html,features='lxml')
#找到职位列表
# html_bs.find() : 查找一个
# html_bs.find_all() : 查找所以符合条件的节点
'''
name = None : 指定要查找的标签名,可以是一个字符串,正则表达式,或列表
attrs = {} : 根据属性的值查找标签(dict){‘属性名称’:‘属性的值’}
text = None : 可以是一个字符串,正则表达式,查找符合条件的文本内容
limit = None : 限制返回的标签的个数
find_all : 返回的标签都放在列表里
'''
tr_even = html_bs.find_all(name='tr',attrs={'class':'even'})
tr_odd = html_bs.find_all(name='tr',attrs={'class':'odd'})
for tr in tr_even + tr_odd:
# print(tr)
jobinfo = {}
# get_text() : 表示取文本
jobinfo['title'] = tr.select('td.l.square > a')[0].get_text()
# 职位的类型
jobinfo['type'] = tr.select('td')[1].get_text()
# jobinfo['type'] = tr.select('td:nth-child(2)').get_text()
#
jobinfo['num'] = tr.select('td')[2].get_text()
jobinfo['address'] = tr.select('td')[3].get_text()
jobinfo['time'] = tr.select('td')[4].get_text()
# 职位详情地址
detail_url = 'https://hr.tencent.com/' + tr.select('td.l.square > a')[0].attrs['href']
# print(detail_url)
# 详情的HTML
html = load_data(detail_url)
# 获取职位要求和描述
jobinfo['content'] = parse_detail_data(html)
print(jobinfo,detail_url)
# 提取url链接
next_url = html_bs.select('a#next')[0].attrs['href']
return next_url
# save_data_to_db(jobinfo)
def parse_detail_data(html):
# 创建BeautifulSoup对象
html_bs = BeautifulSoup(html,features='lxml')
#使用css语法取出li标签
content_li = html_bs.select('ul.squareli li')
content = []
# 取出li标签的文本,放入列表中
for li in content_li:
li_text = li.get_text('')
content.append(li_text)
return','.join(content)
def save_data_to_db(jobinfo): ''' 存储数据 :param jobdata: 字典,存放职位信息 :return: ''' sql = ''' insert into lagou(%s) values(%s)'''%(','.join(jobinfo.keys()), ','.join(['%s']*len(jobinfo)) ) try: cursor.execute(sql, list(jobinfo.values())) db.commit() except Exception as err: print(err) db.rollback() if name == 'main':
db = c.Connect(user="root", password="123456", database="1712B")
cursor = db.cursor()
# 设置起始偏移量
offset = 0
full_url = 'https://hr.tencent.com/position.php?&start=' + str(offset)
tengxunJob(full_url)
create table tengxunzp( id int primary key auto_increment not null comment'id', title varchar(200) comment'标题', type varchar(200) comment'时间', num varchar(200) comment'人数', address varchar(200) comment'活动介绍', time varchar(200) comment'温馨提示', content varchar(200) comment'体验店介绍' ); Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
Tag
Tag 通俗点讲就是 HTML 中的一个个标签,例如:
The Dormouse's story
上面的 title head a p等等 HTML 标签加上里面包括的内容就是 Tag,那么试着使用 Beautiful Soup 来获取 Tags:
from bs4 import BeautifulSoup
【beautifulsoup&pyquery】html = """
The Dormouse's story
Once upon a time there were three little sisters; and their names were
,
Lacie and
Tillie;
and they lived at the bottom of a well.
...
"""
创建 Beautiful Soup 对象 soup = BeautifulSoup(html)
print(soup.title)
print(soup.p)
The Dormouse's story
print(type(soup.p))
对于 Tag,它有两个重要的属性,是 name 和 attrs
print(soup.name)
[document] #soup 对象本身比较特殊,它的 name 即为 [document] print (soup.head.name)
head #对于其他内部标签,输出的值便为标签本身的名称 print (soup.p.attrs)
{'class': ['title'], 'name': 'dromouse'} 在这里,我们把 p 标签的所有属性打印输出了出来,得到的类型是一个字典。 print (soup.p['class'] # soup.p.get('class'))
['title'] #还可以利用get方法,传入属性的名称,二者是等价的 soup.p['class'] = "newClass"
print soup.p # 可以对这些属性和内容等等进行修改
The Dormouse's story
NavigableString
既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如
print (soup.p.string)
The Dormouse's story print (type(soup.p.string))
In [13]:
print type(soup.name)
[document] print soup.attrs # 文档本身的属性为空
{} Comment Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
print soup.a
print soup.a.string
Elsie print type(soup.a.string)
pyquery语法规则类似于Jquery,可以对html文本进行解析
安装 : pip3 install pyquery
pq = PyQuery(html文档)
pq(‘css选择器’)
items():获取到多个标签时,使用items()将PyQuery转换为一个生成器,然后再使用for in 循环
filter(‘css选择器’):过滤
text():获取标签的文本
attr(‘属性名’)获取属性值
.html()和.text() 获取相应的 HTML 块或者文本内容,
p=pq("
获取相应的 HTML 块
print (p('head').html())
获取相应的文本内容
print (p('head').text())
输出:
Hello World!
(selector):通过选择器来获取目标内容,
d = pq(
"test 1
test 2
")
获取元素内的 HTML 块
print (d('div').html())
获取 id 为 item-0 的元素内的文本内容
print (d('#item-0').text())
获取 class 为 item-1 的元素的文本内容
print (d('.item-1').text())
输出:
test 1
test 2
test 1
test 2
.eq(index):根据索引号获取指定元素(index 从 0 开始)
d = pq(
"test 1
test 2
"
)
获取第二个 p 元素的文本内容
print (d('p').eq(1).text())
'''输出
test 2
'''
.find():查找嵌套元素,
d = pq("test 1
test 2
")
查找内的 p 元素
print d('div').find('p')
查找内的 p 元素,输出第一个 p 元素
print d('div').find('p').eq(0)
输出:
test 1
test 2
test 1
.filter():根据 class、id 筛选指定元素,
d = pq("test 1
test 2
")
查找 class 为 item-1 的 p 元素
print d('p').filter('.item-1')
查找 id 为 item-0 的 p 元素
print d('p').filter('#item-0')
输出:
test 2
test 1
.attr():获取、修改属性值,
d = pq("test 1
test 2
")
获取 标签的属性 id
print(d('p').attr('id'))
修改标签的 class 属性为 new
print(d('a').attr('class','new'))
输出:
item-0
test 2
'''
7、其他操作:
添加 class
.addClass(value):
判断是否包含指定的 class,返回 True 或 False
.hasClass(value):
获取子元素
.children():
获取父元素
.parents():
获取下一个元素
.next():
获取后面全部元素块
.nextAll():
获取所有不匹配该选择器的元素
.not_(selector):
eg:
from pyquery import PyQuery
import requests
def tencentJob(full_url):
html = loda_data(full_url)
next_url = parse_page_data(html)
if 'javascript:; ' != next_url:
next_url = 'https://hr.tencent.com/'+next_url
tencentJob(next_url)
def loda_data(url):
"""
发起请求,获取职位列表页页面源码
:param url:
:return:
"""
req_header = {
'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
}
response = requests.get(url,headers=req_header)
if response.status_code == 200:return response.text
def parse_page_data(html):
"""
解析分页的页面源码数据
:param html:
:return:
"""
#实例化一个pyquery对象
html_pq = PyQuery(html)
#提取职位列表
# tr_even = html_pq('tr.even')
#filter过滤
tr_even = html_pq('tr').filter('.even')
tr_odd = html_pq('tr').filter('.odd')
tr_all = tr_even + tr_odd
tr_all = tr_all.items()
#print(tr_all)# tr_even = tr_even.items()
# tr_odd = tr_odd.items()
#
# print(tr_even, tr_odd)
# print(type(tr_even), type(tr_odd))
for tr in tr_all:
# print(tr)
jobinfo = {}
#获取标题(使用.text()取出文本)
jobinfo['title'] = tr('td.l.square a').text()
#取详情地址,a标签的href属性(.attr('属性名'))
detail_url = 'https://hr.tencent.com/'+tr('td.l.square a').attr('href')
#职位类型eq(1):获取之地那个索引的标签,索引值从0开始
jobinfo['type'] = tr('td').eq(1).text()
#招聘人数
jobinfo['needpeople'] = tr('td').eq(2).text()
#地点
jobinfo['adress'] = tr('td').eq(3).text()
#发布时间
jobinfo['publishTime'] = tr('td').eq(4).text()
#工作详情的内容
html = loda_data(detail_url)
jobinfo['content'] = parse_detail_data(html)
print(jobinfo)#提取下一页的url地址
#next_url = html_pq('a').filter('#next')
next_url = html_pq('a#next').attr('href')
return next_url
def parse_detail_data(html):
"""
解析详情数据
:param html:
:return:
"""
#实例化一个pyquery对象
html_pq = PyQuery(html)
#提取详情内容所在的li标签
lis = html_pq('ul.squareli li')
content = []
for li in lis.items():
li_text = li.text()
content.append(li_text)
return ','.join(content)
if name == 'main':
#设置起始偏移量
offset = 0
full_url = 'https://hr.tencent.com/position.php?&start=' + str(offset)
tencentJob(full_url)
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 宋仲基&宋慧乔(我们不公布恋情,我们直接结婚。)
- 21天|21天|M&M《见识》04
- 二叉树路径节点关键值和等于目标值(LeetCode--112&LeetCode--113)
- 2021—3—8日教练实践总结&呼吸练习&觉察日记
- 奇迹-妖妈|奇迹-妖妈 感恩日记46/365&非暴力沟通第3天
- 前端|web前端dya07--ES6高级语法的转化&render&vue与webpack&export
- 数据技术|一文了解Gauss数据库(开发历程、OLTP&OLAP特点、行式&列式存储,及与Oracle和AWS对比)
- Python|Win10下 Python开发环境搭建(PyCharm + Anaconda) && 环境变量配置 && 常用工具安装配置
- gem|gem & pod 记录