1.安装
BS安装: pip install beautifulsoup4
解析器安装:pip install lxml
2.预热
from bs4 import BeautifulSoup
soup = BeautifulSoup(read_file('qiushibaike.html'), 'html.parser')
print type(soup) #
print dir(soup)
# ['ASCII_SPACES', 'DEFAULT_BUILDER_FEATURES', 'HTML_FORMATTERS', 'NO_PARSER_SPECIFIED_WARNING', 'ROOT_TAG_NAME', 'XML_FORMATTERS',
# '__call__', '__class__', '__contains__', '__copy__', '__delattr__', '__delitem__', '__dict__', '__doc__', '__eq__', '__format__',
# '__getattr__', '__getattribute__', '__getitem__', '__getstate__', '__hash__', '__init__', '__iter__', '__len__', '__module__', '__ne__',
# '__new__', '__nonzero__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__',
# '__unicode__', '__weakref__', '_all_strings', '_attr_value_as_string', '_attribute_checker', '_check_markup_is_url', '_feed', '_find_all', '_find_one',
# '_formatter_for_name', '_is_xml', '_lastRecursiveChild', '_last_descendant', '_most_recent_element', '_popToTag', '_select_debug', '_selector_combinators',
# '_should_pretty_print', '_tag_name_matches_and', 'append', 'attribselect_re', 'attrs', 'builder', 'can_be_empty_element', 'childGenerator', 'children', 'clear',
# 'contains_replacement_characters', 'contents', 'currentTag', 'current_data', 'declared_html_encoding', 'decode', 'decode_contents', 'decompose', 'descendants',
# 'encode', 'encode_contents', 'endData', 'extract', 'fetchNextSiblings', 'fetchParents', 'fetchPrevious', 'fetchPreviousSiblings', 'find', 'findAll', 'findAllNext',
# 'findAllPrevious', 'findChild', 'findChildren', 'findNext', 'findNextSibling', 'findNextSiblings', 'findParent', 'findParents', 'findPrevious', 'findPreviousSibling',
# 'findPreviousSiblings', 'find_all', 'find_all_next', 'find_all_previous', 'find_next', 'find_next_sibling', 'find_next_siblings', 'find_parent', 'find_parents',
# 'find_previous', 'find_previous_sibling', 'find_previous_siblings', 'format_string', 'get', 'getText', 'get_text', 'handle_data', 'handle_endtag', 'handle_starttag',
# 'has_attr', 'has_key', 'hidden', 'index', 'insert', 'insert_after', 'insert_before', 'isSelfClosing', 'is_empty_element', 'is_xml', 'known_xml', 'markup', 'name',
# 'namespace', 'new_string', 'new_tag', 'next', 'nextGenerator', 'nextSibling', 'nextSiblingGenerator', 'next_element', 'next_elements', 'next_sibling', 'next_siblings',
# 'object_was_parsed', 'original_encoding', 'parent', 'parentGenerator', 'parents', 'parse_only', 'parserClass', 'parser_class', 'popTag', 'prefix', 'preserve_whitespace_tag_stack',
# 'preserve_whitespace_tags', 'prettify', 'previous', 'previousGenerator', 'previousSibling', 'previousSiblingGenerator', 'previous_element', 'previous_elements', 'previous_sibling',
# 'previous_siblings', 'pushTag', 'quoted_colon', 'recursiveChildGenerator', 'renderContents', 'replaceWith', 'replaceWithChildren', 'replace_with', 'replace_with_children',
# 'reset', 'select', 'select_one', 'setup', 'string', 'strings', 'stripped_strings', 'tagStack', 'tag_name_re', 'text', 'unwrap', 'wrap']
# 文档内容被转化为Unicode编码类型
print type(soup.title.name)
# print soup.prettify() # 以标准格式展示出html内容
print soup.title # 输出带有标签的元素 : 糗事百科 - 超搞笑的原创糗事笑话分享社区
print type(soup.title) #
print soup.title.name # title
print soup.title.string # 糗事百科 - 超搞笑的原创糗事笑话分享社区
# head (注:<由于网站有未闭合的标签,导致该结果输出可能是meta>
print soup.title.parent.name
# 战争女神希维尔的回旋之刃
注:为什么就输出一个元素呢,是因为该形式的属性访问只输出匹配到的第一个元素
print soup.p
# 该方法的返回结果为一个列表,包含所有的a标签的元素 [\n\u7cd7\u4e8b\u767e\u79d1
\n, \u70ed\u95e8,....]
print soup.find_all('a')
print soup.find(id="highlight") # 返回到匹配到的单个元素热门
print soup.find(id='zhaojunwei') # 如果未匹配到结果,返回值为None
print soup.find(class_="share-qq") # 该方法也是只返回匹配到的第一个元素
print '--------------------'
for link in soup.find_all('a'):
print(link.get('href')) # 输出标签元素的href属性。
3.对象介绍
1> . Tag对象
from bs4 import BeautifulSoup
soup = BeautifulSoup(read_file('qiushibaike.html'), 'html.parser')
print soup.title # 输出带有标签的元素 : 糗事百科 - 超搞笑的原创糗事笑话分享社区
print type(soup.title) #
2>.NavigableString对象
from bs4 import BeautifulSoup
soup = BeautifulSoup(read_file('qiushibaike.html'), 'html.parser')
print type(soup.find(id='c-118910070').findChild('i', class_='number').string) #
3>.BeautifulSoup,Comment对象
经过BeautifulSoup类实例化的对象就是Beautifulsoup对象类型,Comment对象为实例化后的BeautifulSoup中备注的标签元素
4.属性方法介绍
print soup.find(id="highlight").attrs # {u'href': u'/', u'id': u'highlight', u'rel': [u'nofollow']}
print soup.find(class_="stats-buttons")['class'] # [u'stats-buttons', u'bar', u'clearfix'] 多值属性
print soup.find(id='c-118910070')
print soup.find(id='c-118910070').string # 该内容为空的原因为当前节点有很多子节点,.string不知道要输出哪个子节点的内容,可以.strings属性来输出所有内容
print soup.find(id='c-118910070').strings #.strings属性的结果为一个生成器对象,遍历可输出所有子节点的.string属性结果
# for j in [i for i in soup.find(id='c-118910070').strings]: #stripped_strings 会去掉多余的空白
# print j
print type(soup.find(id='c-118910070').findChild('i', class_='number').string) #
# print soup.head.title # 糗事百科 - 超搞笑的原创糗事笑话分享社区
#[u'\n', , u'\n',
# , u'\n', , u'\n',
# , u'\n', \u7cd7\u4e8b\u767e\u79d1 - \u8d85\u641e\u7b11\u7684\u539f\u521b\u7cd7\u4e8b\u7b11\u8bdd\u5206\u4eab\u793e\u533a ,
# u'\n', ,
# u'\n', , u'\n', , u'\n', , u'\n', ,
# u'\n', ,
# u'\n', ,
# u'\n', , u'\n']
# print soup.head.contents #所有子节点以列表的形式输出
# for i in soup.head.children:
# soup.head.children 是一个生成器,包含所有的子节点,内容和soup.head.contents相同
# print i
print soup.head.descendants #
# for i in soup.head.descendants:
#.descendants 属性可以对所有tag的子孙节点进行递归循环
# print i
# print soup.find('div', class_='thumb')
# print soup.find('div', class_='thumb').parent # 父节点的所有内容
#实际文档中的tag的 .next_sibling 和 .previous_sibling 属性通常是字符串或空白. 为什么呢,是因为前后元素标签之间的顿号和换行符
print soup.find('div', class_='stats').find(class_='stats-vote').next_sibling # 该属性返回的是元素的兄弟元素
print soup.find('div', class_='stats').find(class_='stats-vote').next_siblings # 该属性返回的是元素的兄弟元素们的生成器
# next_element属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的.
# 通过 .next_elements 和 .previous_elements 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样
print soup.find('div', class_='stats').find(class_='stats-vote').next_element.next_element # 该属性返回的是元素的下一个元素
# print dir(soup.find('div', class_='stats').find(class_='stats-vote'))
print soup.find('div', class_='stats').find(class_='stats-vote').previous_sibling
print soup.find('div', class_='stats').find(class_='stats-vote').previous_element
# for tag in soup.find_all(re.compile(r'^t')):
# #所有一t开头的标签元素
# print tag.name
# for tag in soup.find_all(['a', 'b']):
# #所有a元素和所有b元素
# print tag.name
## 如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 [4] ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
print soup.find_all(has_class_but_no_id)
5.find_all()方法介绍
class ResultSet(list):
"""A ResultSet is just a list that keeps track of the SoupStrainer
that created it."""
def __init__(self, source, result=()):
super(ResultSet, self).__init__(result)
self.source = source
def _find_all(self, name, attrs, text, limit, generator, **kwargs):
"Iterates over a generator looking for things that match."
if text is None and 'string' in kwargs:
text = kwargs['string']
del kwargs['string']
if isinstance(name, SoupStrainer):
strainer = name
else:
strainer = SoupStrainer(name, attrs, text, **kwargs)
if text is None and not limit and not attrs and not kwargs:
if name is True or name is None:
# Optimization to find all tags.
result = (element for element in generator
if isinstance(element, Tag))
return ResultSet(strainer, result)
elif isinstance(name, basestring):
# Optimization to find all tags with a given name.
result = (element for element in generator
if isinstance(element, Tag)
and element.name == name)
return ResultSet(strainer, result)
results = ResultSet(strainer)
while True:
try:
i = next(generator)
except StopIteration:
break
if i:
found = strainer.search(i)
if found:
results.append(found)
if limit and len(results) >= limit:
break
return results
def find_all(self, name=None, attrs={}, recursive=True, text=None, limit=None, **kwargs):
"""Extracts a list of Tag objects that match the given
criteria. You can specify the name of the Tag and any
attributes you want the Tag to have.
The value of a key-value pair in the 'attrs' map can be a
string, a list of strings, a regular expression object, or a
callable that takes a string and returns whether or not the
string matches for some custom definition of 'matches'. The
same is true of the tag name."""
generator = self.descendants
if not recursive:
generator = self.children
return self._find_all(name, attrs, text, limit, generator, **kwargs)
findAll = find_all # BS3
findChildren = find_all # BS2
可以使用tag的name来查询:soup.find_all('div')
可以使用keyword关键字:soup.find_all(id='highlight')
soup.find_all(href=re.compile("pictures"))
soup.find_all(href=re.compile("elsie"), id='link1')
可以使用css查询:soup.find('div', class_='stats')
可以使用string参数来查询:
soup.find_all(string="Elsie")
# [u'Elsie']
soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']
soup.find_all(string=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]
def is_the_only_string_within_a_tag(s):
""Return True if this string is the only child of its parent tag.""
return (s == s.parent.string)
soup.find_all(string=is_the_only_string_within_a_tag)
# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']
limit参数,查询的结果达到limit的值后就不在搜索
如果只想搜索tag的直接子节点,可以使用参数 recursive=False
6.find(),find_parent(),find_parents(),find_next_siblings(),find_next_sibling(),find_previous_siblings(),find_previous_sibling(),
find_all_next(),find_next(),find_all_previous(),find_previous()不在一一介绍。
7.css选择器
在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数, 即可使用CSS选择器的语法找到tag:
soup.select("body a")
# [Elsie,
# Lacie,
# Tillie]
soup.select("html head title")
# [The Dormouse's story ]
soup.select("#link1")
# [Elsie]
soup.select(".sister")
# [Elsie,
# Lacie,
# Tillie]
soup.select_one(".sister")
# Elsie