所以我用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!'
答案 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>
请重复test
和test2
。
我认为您打算将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>