简单的蜘蛛与BS4神秘地翻倍每页

时间:2015-12-26 04:15:34

标签: python beautifulsoup web-crawler

所以我用BS4编写了一个非常简单的单级深蜘蛛。目标是令人讨厌的html书籍在线格式(如在文档中),其中有一个目录页面,然后所有内容都在从主要ToC页面链接的页面上。假设所有内容都是vanilla html。目标是为离线阅读保存这类东西。因此,该技术只需在主页面上创建一个唯一链接列表,从每个链接中获取内容,并将整个内容连接到一个大的html页面,然后可以在闲暇时离线阅读。

除了一个小小的疯狂错误之外它完美无缺:在最终的html文件中,每个子页面出现两次。完全两次。我一直在这个bash脚本教程http://www.tldp.org/LDP/Bash-Beginners-Guide/html/上测试它(我没有权利,顺便说一下,虽然版权条款允许复制,所以请不要在任何抨击服务器或否则是不礼貌的)。

我检查了什么:

  • 我已经确认基础网页本身并不包含隐藏在其中的重复内容。

  • 我已经确认uniques确实包含一系列唯一链接。

  • 我已按预期验证len(texts) == len(uniques) + 1

现在真的开始让我感到困惑。这可能是某种明显的愚蠢错误,但我根本看不到它而且我疯了。谁能看到这里出了什么问题?谢谢!

from bs4 import BeautifulSoup as BS
import urllib 

def clearJunk(BSobj):
    [s.extract() for s in BSobj(['style', 'script'])]

def makeSoup(url):
    r = urllib.urlopen(url)
    soup = BS(r)
    clearJunk(soup)
    return soup

def getBody(BSobj):
    return ' '.join([str(i) for i in BSobj.find('body').findChildren()])

def stripAnchor(url):
    badness = url.find('#')
    if badness != -1:
        return url[:badness]
    return url

url = raw_input('URL to crawl: ')
soup = makeSoup(url)

links = filter(lambda x: 'mailto:' not in x, [url + stripAnchor(alink['href']) for alink in soup.find_all('a', href=True)])
uniques = [s for (i,s) in enumerate(links) if s not in links[0:i]]

texts = [getBody(makeSoup(aurl)) for aurl in uniques]
texts.insert(0, getBody(soup))
from time import gmtime, strftime
filename = 'scrape' + str(strftime("%Y%m%d%H%M%S", gmtime())) + '.html'
with open(filename, 'w') as outfile:
    outfile.write('<br><br>'.join(texts))

print 'scraping complete!'

1 个答案:

答案 0 :(得分:1)

问题在于您在body中找到getBody()标记的子项。默认情况下,它以递归方式,示例:

from bs4 import BeautifulSoup

data = """
<body>
    <div>
        <b>test1</b>
    </div>
    <div>
        <b>test2</b>
    </div>
</body>
"""

soup = BeautifulSoup(data, "html.parser")
for item in soup.find('body').findChildren():
    print(item)

它会打印出来:

<div>
<b>test1</b>
</div>
<b>test1</b>
<div>
<b>test2</b>
</div>
<b>test2</b>

请重复testtest2

我认为您打算将find_all()用于recursive=False

' '.join([str(i) for i in BSobj.find('body').find_all(recursive=False)])

这是上面提供的示例HTML的输出结果:

>>> for item in soup.find('body').find_all(recursive=False):
...     print(item)
... 
<div>
<b>test1</b>
</div>
<div>
<b>test2</b>
</div>