Beautifulsoup 爬取页面试题

假设有一个页面,页面中有n道选择题,每道选择题有若干个选项。题干部分用h6 标签标记。选项部分用的是td 下的div 标签。如下图所示:

整个页面是将如下的HTML 段落循环n次。

    
<div style="" class="qItemType qItemDetail1" value="10000#1" id="quest2436">                                    
    <div>
        <div class="breadcrumb">
            <div>
                <ul style="list-style-type:none;">
                    <li><h6><a name="qnum1" style="color: red;">第1题.</a>&nbsp;&nbsp;选一二三还是四五六呢。</h6></li>
                </ul>
            </div>
            <ul style="list-style-type:none">
                <li>
                    <table>                                                
                        <tbody><tr>
                                 <td>
                                    <div>A.一二三</div>        
                                 </td>
                                </tr>
                                <tr>
                                  <td>
                                     <div>B.四五六</div>                    
                                  </td>
                                 </tr>                                            
                         </tbody></table>
                 </li>
            </ul>
        </div>            
<div>                                

 下面想要用beautifulsoup 库中的方法将页面上的题目和选项提取出来。

首先要引入需要用到的包:

from bs4 import BeautifulSoup
from urllib import request,parse
import re

然后可以用多种方法提取页面源码,:

#既可以打开一个html文件:
soup = BeautifulSoup(open("page_source_code.html"))
#或者直接传入HTML代码:
soup = BeautifulSoup("<html>data</html>")
#也可以发送并且拦截请求:
url = “http://fake.html” response = request.urlopen(url,timeout = 20) responseUTF8 = response.read().decode("utf-8") soup = BeautifulSoup(responseUTF8,'lxml')

 总之,这样我们就得到了一个soup 对象。接下来只要根据对象的标签结构,通过一定方法定位到目标标签,就可以了。

方法一:下面这种方法比较基本,用的是“绝对路径”找寻标签

# 通过观察发现,题干部分全部都是h6标签,和h6标签下的a标签。页面其余部分没有用到h6标签,所以用.find_all方法来抓取所有的题干。得到一个标签 list
h6lbs = soup.find_all('h6')
# 定义一个二维数组,用来盛放抓取到的选择题。选择题的题干和选项可作为每一个数组成员的成员。
item_question = []
for i in range(len(h6lbs)):
    #定义一个一维数组,可以用来盛放题干和选项。先把刚刚拿到的题干保存进数组中
    item = []
    item.append(h6lbs[i].text)
    #通过以上的HTML 结构可以知道,找到题干后,题干标签的“太爷爷”的“三弟弟”是保存选项的地方,所以这里用了很多个.parent 和 .next_sibling方法,通过绝对路径的方式定位标签
    tag1 = h6lbs[i].parent.parent.parent.next_sibling.next_sibling
    # check if this is choice question. or it must be a Yes/No questionnaire
    if tag1 is not None and tag1.li is not None:
        #刚刚说到太爷爷的三弟弟是存放选项的地方。太爷爷的三弟弟下的li标签下的table标签下的tbody标签下存放了多个选项,从这里开始需要遍历,将每一个选项都提取出
        tag = h6lbs[i].parent.parent.parent.next_sibling.next_sibling.li.table.tbody
        for child in tag.children:
            #因为抓取出来有空对象,所以此处加入了一个判断。如果是None,就不保存了。
            if child.string is None:
                tag_string = child.td.div.string
                #遍历每一个标签,取出其中的选项内容,用.string方法
                #将取到的选项内容加入刚刚创建的一维数组中
                item.append(tag_string)
        # print(item)
    #将每次得到的一维数组保存进二维数组中
    item_question.append(item)
print(item_question)

方法二(推荐):还可以用相对路径的方法定位标签:

#通过观察可以发现,每一个试题都是在一个div标签,并且value 为11111#1,11111#2,11111#3的标签下的。所以我们先将这个标签取到,作为一个参照。re.compile是正则表达式方法
the_tag = soup.find_all('div',value = re.compile('11111#\d'))
print(len(the_tag))
#创建二维数组,用来保存试题
item_question = []
for tag in the_tag:
    #创建一维数组,用来保存题干和选项
    item = []
    #遍历刚刚选好的参照标签 
    for child_tag in tag.descendants:
        #每一个参照标签下的h6标签都是题干,提取出来保存。 
        if child_tag.name == "h6":
            item.append(child_tag.get_text("", strip=True))
        #每一个参照标签下的td标签都是选项,提取出来保存
        elif child_tag.name == "td":
            if child_tag.div is not None:
                item.append(child_tag.div.get_text("", strip=True))
    item_question.append(item)
print(item_question)
posted @ 2019-09-13 12:34  Elaine_Septer  阅读(719)  评论(0编辑  收藏  举报