【问题标题】:Scrape information from challenging website with no guiding HTML structure从没有指导性 HTML 结构的具有挑战性的网站中抓取信息
【发布时间】:2016-09-25 07:11:09
【问题描述】:

我需要从一个非常具有挑战性的网站上抓取一些信息

这是一个例子:

<div class="overview">
        <span class="course_titles">Courses:</span> 
        <a href="/schools/courses/173/" class="course_name">Math101</a> (Math; Monday; Room 10);
        <a href="/schools/student/1388/" class="coursestudent_name">Mark</a> 17, 
        <a href="/schools/student/1401/" class="coursestudent_name">Alex</a> 18, ), 

        <a href="/schools/courses/2693/" class="course_name">English101</a> (English; Thursdays; Room 12); 
        <a href="/schools/student/1403/" class="coursestudent_name">Sarah</a> 16, 
        <a href="/schools/student/1411/" class="coursestudent_name">Nancy</a> 17, 
        <a href="/schools/student/1390/" class="coursestudent_name">Casey</a> 17 ), 
</div>

每门课程都有特定的学生,他们的名字后面写着他们的年龄(那些随机字符已经在里面了)。

我需要和他们各自的学生一起学习每门课程,再加上年龄。

不幸的是,除了包罗万象的 div 类之外,没有固有的层次结构。我尝试通过“course_name”使用 BeautifulSoup 进行抓取,然后添加所有具有“coursestudent_name”属性的项目,但这样我会将所有学生添加到每门课程中。

我希望我可以更改网站,但我不能。任何人都知道如何获得正确学生的每门课程信息?

谢谢!

【问题讨论】:

  • 你能清楚地说明你想要的输出吗?

标签: python regex web-scraping beautifulsoup


【解决方案1】:

您可以主要使用 BeautifulSoup,然后使用一点点正则表达式来获取不在任何 html 标签内的学生年龄

soup = BeautifulSoup(html, "html.parser")
allA = soup.find("div", {"class" : "overview"}).find_all("a")

classInfo = {}
currentClass = None
for item in allA:
    if item['class'] == ['course_name']:
        classInfo[item.text] = []
        currentClass = item.text
    else:
        classInfo[currentClass] += [(item.text, int(re.search(item.text + r"</a> (\d+)", html).group(1)))]


print(classInfo)

这个输出:

{'English101': [('Sarah', 16), ('Nancy', 17), ('Casey', 17)], 'Math101': [('Mark', 17), ('Alex', 18)]}

【讨论】:

    【解决方案2】:

    如果您可以修改您的问题,让我们知道您正在寻找什么。但是,这里有一个基本示例,说明如何从该页面获取数据。

    from bs4 import BeautifulSoup
    import re
    
    html = '''<div class="overview">
            <span class="course_titles">Courses:</span> 
            <a href="/schools/courses/173/" class="course_name">Math101</a> (Math; Monday; Room 10);
            <a href="/schools/student/1388/" class="coursestudent_name">Mark</a> 17, 
            <a href="/schools/student/1401/" class="coursestudent_name">Alex</a> 18, ), 
    
            <a href="/schools/courses/2693/" class="course_name">English101</a> (English; Thursdays; Room 12); 
            <a href="/schools/student/1403/" class="coursestudent_name">Sarah</a> 16, 
            <a href="/schools/student/1411/" class="coursestudent_name">Nancy</a> 17, 
            <a href="/schools/student/1390/" class="coursestudent_name">Casey</a> 17 ), 
    </div>'''
    
    soup = BeautifulSoup(html)
    
    all_links = soup.find_all('a')
    
    dict_courseinfo = {}
    dict_key = ''
    stu_lst = []
    
    for n, link in enumerate(all_links):
        if link.get('class')[0] == 'course_name':
            if n > 0:
                dict_courseinfo[dict_key] = stu_lst
                stu_lst = []
            dict_key = str(link.text)
        else:
            age = int(re.search(link.text + r"</a> (\d+)", html).group(1))
            stu_lst.append((str(link.text), age))
    
    dict_courseinfo[dict_key] = stu_lst
    
    print dict_courseinfo
    

    将输出:

    {'Math101': [('Mark', 17), ('Alex', 18)], 'English101': [('Sarah', 16), ('Nancy', 17), ('Casey', 17)]}
    

    【讨论】:

      【解决方案3】:

      您不需要正则表达式,您可以简单地解析锚标签以获取名称并调用next_sibling 获取年龄文本拆分和剥离以获取年龄文本,找到@ 之前的course_name 987654323@也会给你相关课程:

      h = """<div class="overview">
              <span class="course_titles">Courses:</span>
              <a href="/schools/courses/173/" class="course_name">Math101</a> (Math; Monday; Room 10);
              <a href="/schools/student/1388/" class="coursestudent_name">Mark</a> 17,
              <a href="/schools/student/1401/" class="coursestudent_name">Alex</a> 18, ),
      
              <a href="/schools/courses/2693/" class="course_name">English101</a> (English; Thursdays; Room 12);
              <a href="/schools/student/1403/" class="coursestudent_name">Sarah</a> 16,
              <a href="/schools/student/1411/" class="coursestudent_name">Nancy</a> 17,
              <a href="/schools/student/1390/" class="coursestudent_name">Casey</a> 17 ),
      </div>"""
      
      from bs4  import BeautifulSoup
      soup = BeautifulSoup(h)
      
      
      data = [[a.find_previous("a", "course_name").text ,a.text, a.next_sibling.split()[0].strip(",")] for a in soup.select("div.overview a.coursestudent_name")]
      
       [[u'Math101', u'Mark', u'17'], [u'Math101', u'Alex', u'18'], [u'English101', u'Sarah', u'16'], [u'English101', u'Nancy', u'17'], [u'English101', u'Casey', u'17']]
      

      【讨论】:

        猜你喜欢
        • 2013-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-18
        • 1970-01-01
        相关资源
        最近更新 更多