Rui

python爬虫教程和遇到的坑
下面是来演示如何使用BeautifulSoup模块来从HTML文本中提取我们想要的数据。前言BeautifulSo...
扫描右侧二维码阅读全文
07
2019/08

python爬虫教程和遇到的坑

下面是来演示如何使用BeautifulSoup模块来从HTML文本中提取我们想要的数据。

前言

BeautifulSoup 有多个版本,我们使用BeautifulSoup4。详细使用看BeautifuSoup4官方文档。然后我们安装lxml,这是一个解析器,BeautifulSoup可以使用它来解析HTML,然后提取内容。

推荐使用pycharm的管理模块包:
pycharm64_2019-08-07_16-01-02.png

文档解析器对照表如下:
chrome_2019-08-07_16-02-39.png

BeautifulSoup 库的使用

网上找到的几个官方文档:BeautifulSoup4.4.0中文官方文档,BeautifulSoup4.2.0中文官方文档。不同版本的用法差不多,几个常用的语法都一样。

首先来看BeautifulSoup的对象种类,在使用的过程中就会了解你获取到的东西接下来应该如何操作。

BeautifulSoup对象的类型

Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象。所有对象可以归纳为4种类型: Tag , NavigableString , BeautifulSoup , Comment 。下面我们分别看看这四种类型都是什么东西。

Tag

这个就跟HTML或者XML(还能解析XML?是的,能!)中的标签是一样一样的。我们使用find()方法返回的类型就是这个(插一句:使用find-all()返回的是多个该对象的集合,是可以用for循环遍历的。)。返回标签之后,还可以对提取标签中的信息。

提取标签的名字:

tag.name

提取标签的属性:

tag['attribute']

我们用一个例子来了解这个类型:

from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""
soup = BeautifulSoup(html_doc, 'lxml')  #声明BeautifulSoup对象
find = soup.find('p')  #使用find方法查到第一个p标签
print("find's return type is ", type(find))  #输出返回值类型
print("find's content is", find)  #输出find获取的值
print("find's Tag Name is ", find.name)  #输出标签的名字
print("find's Attribute(class) is ", find['class'])  #输出标签的class属性值

NavigableString

NavigableString就是标签中的文本内容(不包含标签)。获取方式如下:

tag.string

还是以上面那个例子,加上下面这行,然后执行:

print('NavigableString is:', find.string)

BeautifulSoup

BeautifulSoup对象表示一个文档的全部内容。支持遍历文档树和搜索文档树。

Comment

这个对象其实就是HTML和XML中的注释。

markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
type(comment)
 <class 'bs4.element.Comment'>
有些时候,我们并不想获取HTML中的注释内容,所以用这个类型来判断是否是注释。

if type(SomeString) == bs4.element.Comment:
    print('该字符是注释')
else:
    print('该字符不是注释')

## BeautifulSoup遍历方法
###节点和标签名
可以使用子节点、父节点、 及标签名的方式遍历:

soup.head #查找head标签
soup.p #查找第一个p标签

对标签的直接子节点进行循环
for child in title_tag.children:
    print(child)

soup.parent #父节点
所有父节点
for parent in link.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)

兄弟节点
sibling_soup.b.next_sibling #后面的兄弟节点
sibling_soup.c.previous_sibling #前面的兄弟节点

所有兄弟节点
for sibling in soup.a.next_siblings:
    print(repr(sibling))

for sibling in soup.find(id="link3").previous_siblings:
    print(repr(sibling))

搜索文档树

最常用的当然是find()和find_all()啦,当然还有其他的。比如find_parent() 和 find_parents()、 find_next_sibling() 和 find_next_siblings() 、find_all_next() 和 find_next()、find_all_previous() 和 find_previous() 等等。
我们就看几个常用的,其余的如果用到就去看官方文档哦。

find_all()

搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件。返回值类型是bs4.element.ResultSet。
完整的语法:

find_all( name , attrs , recursive , string , **kwargs )

这里有几个例子

soup.find_all("title")
# [<title>The Dormouse's story</title>]
#
soup.find_all("p", "title")
# [<p class="title"><b>The Dormouse's story</b></p>]
# 
soup.find_all("a")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
#
soup.find_all(id="link2")
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
#
import re
soup.find(string=re.compile("sisters"))
# u'Once upon a time there were three little sisters; and their names were\n'
name 参数:可以查找所有名字为 name 的tag。
attr 参数:就是tag里的属性。
string 参数:搜索文档中字符串的内容。
recursive 参数: 调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点。如果只想搜索tag的直接子节点,可以使用参数 recursive=False 。

find()

与find_all()类似,只不过只返回找到的第一个值。返回值类型是bs4.element.Tag。
完整语法:
find( name , attrs , recursive , string , **kwargs )

看例子:
soup.find('title')
# <title>The Dormouse's story</title>
#
soup.find("head").find("title")
# <title>The Dormouse's story</title>

基本功已经练完,开始实战!


出现的错误:

1.Python:object of type 'Response' has no len(),如何解决?(点我)
Traceback (most recent call last):
  File "F:/Python/TD.py", line 7, in <module>
    soup = BeautifulSoup(wb_data,'lxml')
  File "C:\Python35\lib\site-packages\bs4\__init__.py", line 192, in __init__
    elif len(markup) <= 256 and (
TypeError: object of type 'Response' has no len()

You are getting response.content. But it return response body as bytes (docs). But you should pass str to BeautifulSoup constructor (docs). So you need to use the response.text instead of getting content.

正确解决方案:

soup = BeautifulSoup(htmlstr.text, 'lxml')

一个抽取自己博客头图的代码

url='http://imgki.com'
htmlstr=requests.get(url,headers=headers)
soup = BeautifulSoup(htmlstr.text, 'lxml')
all_div=soup.find_all('div','item-thumb lazy')
for a in all_div:
    image=a["style"]
    print(image[image.index("(")+1:-1])

在就是把代码封装一下:

import requests
from bs4 import BeautifulSoup
import os

class BeautifulPicture():

    def __init__(self):
        self.headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36'} # 给请求指定一个请求头来模拟chrome浏览器
        self.web_url = 'https://imgki.com'  # 要访问的网页地址
        self.folder_path = 'D:\BeautifulPicture'

    def request(self,url):
        htmlstr=requests.get(url,headers=self.headers)
        return htmlstr

    def mkdir(self,path):
        path=path.strip()
        isexist=os.path.exists(path)
        if not isexist:
            print('创建名字叫做', path, '的文件夹')
            os.makedirs(path)
            print('创建成功!')
        else:
            print(path, '文件夹已经存在了,不再创建')

    def save_img(self,url,name):
        print("save begin")
        img=self.request(url)
        file_name=name+'.jpg'
        f=open(file_name,'ab')
        f.write(img.content)
        print("save ok")
        f.close()

    def get_pic(self):
        self.mkdir(self.folder_path)
        os.chdir(self.folder_path)
        htmlstr=self.request(self.web_url)
        soup= BeautifulSoup(htmlstr.text, 'lxml')
        all_div = soup.find_all('div', 'item-thumb lazy')
        i=1
        for a in all_div:
            image = a["style"]
            img_url=image[image.index("(") + 1:-1]
            print(img_url)
            self.save_img(img_url,str(i))
            i=i+1

bea=BeautifulPicture()
bea.get_pic()

参考博主:https://www.cnblogs.com/Albert-Lee/

Last modification:August 7th, 2019 at 05:49 pm

Leave a Comment