爬虫学习之beautifulsoup

1. Beautiful Soup库入门

Beautiful Soup 是用Python写的一个HTML/XML的解析器,主要用于解析和提取 HTML/XML 数据,它可以很好的处理不规范标记并生成剖析树(parse tree)。

  • 优点1:提供简单又常用的导航(navigating),搜索以及修改剖析树的操作。

  • 优点2:用来解析 HTML 比较简单,API非常人性化,支持CSS选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。

  • 缺点1:基于HTML DOM 的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml

  • 缺点2:匹配效率还是远远不如正则以及xpath的,一般不推荐使用,推荐正则的使用。

2. 使用beautifulsoup提取内容

举例的html代码

<html>
    <head>
        <title>Page title</title>
    </head>
    <body>
        <p id="firstpara" align="center">
        This is paragraph<b>one</b>.
        </p>
        <p id="secondpara" align="blah">
        This is paragraph<b>two</b>.
        </p>
     </body>
</html>

2.1 初始化

import requests
from bs4 import BeautifulSoup
soup = BeautifulSoup(html) # html为html源代码字符串,type(html) == str

2.2 用tag获取相应代码块的剖析树

#当用tag作为搜索条件时,我们获取的包含这个tag块的剖析树:
#<tag><xxx>ooo</xxx></tag>
#这里获取head这个块
head = soup.find('head')
# or
# head = soup.head
# or
# head = soup.contents[0].contents[0]

运行后,我们会得到:

<head>
    <title>Page title</title>
</head>

2.3 用contents[], parent, nextSibling, previousSibling寻找父子兄弟tag

为了更加方便灵活的分析html代码块,beautifulSoup提供了几个简单的方法直接获取当前tag块的父子兄弟。

假设我们已经获得了body这个tag块,我们想要寻找<html>, <head>, 第一个<p>, 第二个<p>这四个tag块:

# body = soup.bodyhtml = body.parent # html是body的父亲
head = body.previousSibling # head和body在同一层,是body的前一个兄弟
p1 = body.contents[0] # p1, p2都是body的儿子,我们用contents[0]取得p1
p2 = p1.nextSibling # p2与p1在同一层,是p1的后一个兄弟, 当然body.content[1]也可得到

print p1.text
# u'This is paragraphone.'
print p2.text
# u'This is paragraphtwo.'
#  注意:1,每个tag的text包括了它以及它子孙的text。2,所有text已经被自动转
#为unicode,如果需要,可以自行转码encode(xxx)

2.4 用find, findParent, findNextSibling, findPreviousSibling寻找祖先或者子孙 tag

有了上面的基础,这里应该很好理解了,例如find方法(我理解和findChild是一样的),就是以当前节点为起始,遍历整个子树,找到后返回。

而这些方法的复数形式,会找到所有符合要求的tag,以list的方式放回。他们的对应关系是:find->findall, findParent->findParents, findNextSibling->findNextSiblings…

如:

print soup.findAll('p')

3 使用beautifulsoup提取丁香园论坛的特定帖子的所有回复内容,以及回复人的信息。

丁香园直通点:晕厥待查——请教各位同仁 - 心血管专业讨论版 -丁香园论坛

import requests
import json
import re
import os
import time

#定义爬取内容方法
def spider_parse_detail(dxy_url):
    ret=requests.get(dxy_url,headers=headers)
    #判断状态码
    if ret.status_code==200:
        #将数据转化为字典
        dxy_response=ret.content.decode()
        content_dict=json.loads(dxy_response)
        #获取字典body内容
        body_data=content_dict.get('items','无对应的key')
        #取出username,body
        for answer_content in body_data:
            username=answer_content.get('username')
            body=answer_content.get('body')
            if 'img' in body:
                body='图片地址:'.join(re.findall('(.*?)<br />.*?src="(.*?)"',body,re.S)[0])
            if 'div' in body:
                body=''.join(re.findall('<div class="quote"><blockquote><strong>(.*?) </strong><br />(.*?)<br /></blockquote></div><br />(.*?)',body,re.S)[0])
            if '<br />' in body:
                body=body.replace('<br />','')
            if '<a' in body:
                body=''.join(re.findall('(.*?)<a href="(.*?).*?".*?</a>',body,re.S)[0])
            write_content(username+'\n'+body)
    else:
        print('状态码为:{}'.format(ret.status_code))

def write_content(movie_info):
    '''
    将解析后的内容写入一个txt的文档中
    '''
    path=os.getcwd()+'\\spider_db\\dxy.txt'
    if os.path.exists('spider_db'):
        with open(path, 'a+', encoding='utf-8') as fp:
            fp.write(movie_info+'\n')
    else:
        os.makedirs('spider_db')
        with open(path, 'a+', encoding='utf-8') as fp:
            fp.write(movie_info+'\n')

if __name__=="__main__":
    url = 'http://3g.dxy.cn/bbs/bbsapi/mobile?s=view_topic&checkUserAction=1&withGood=1&order=0&size=20&id=509959&page={}'
    headers = {
        'Referer': 'http://3g.dxy.cn/bbs/topic/509959',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36',
        'Cookie': 'JUTE_SESSION_ID=567f29a6-000d-4161-848b-adb1ccd8d14d; JUTE_TOKEN=698ac7db-3491-435c-b379-223efbb784dfc6cd; JSESSIONID=AEBB632348E91AA71812223efbb784dfc6cd; JUTE_BBS_DATA=223efbb784dfc6cd206b4154065fd15547a0b2c6803aa79eb959b8464f8bb7da9b70ce1da417dd3f4228beefe465f87a269b9537c1bfaf109be0fd1f901501e395b2ee4ed6eddd37ab44306aa3b8965c; CMSSESSIONID=86F6AB86D56642969DBA83223efbb784dfc6cd; __asc=df7da97c1694223efbb784dfc6cd2; __auc=df7223efbb784dfc6cd20e2; DXY_USER_GROUP=61; JUTE_SESSION=ae5de03931ec9b223efbb784dfc6cd7c20ebac5eba22806da380df6f37b4c381387522f5e1819f2ec7c126987e65d0acaabd8c3cdebaa47ce4214c739baf870a1a895d03e50'
    }
    for page in range(1,3):
        spider_parse_detail(url.format(page))
        time.sleep(1)

爬取结果:
​​​​在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值