BeautifulSoup - 抓取论坛页面
Posted
技术标签:
【中文标题】BeautifulSoup - 抓取论坛页面【英文标题】:BeautifulSoup - scraping a forum page 【发布时间】:2014-03-25 05:25:27 【问题描述】:我正在尝试抓取论坛讨论并将其导出为 csv 文件,其中包含“主题标题”、“用户”和“帖子”等行,其中后者是每个人的实际论坛帖子。
我是 Python 和 BeautifulSoup 的完整初学者,所以我很难做到这一点!
我当前的问题是所有文本在 csv 文件中的每行都拆分为一个字符。有没有人可以帮助我?如果有人能帮帮我,那就太好了!
这是我一直在使用的代码:
from bs4 import BeautifulSoup
import csv
import urllib2
f = urllib2.urlopen("https://silkroad5v7dywlc.onion.to/index.php?action=printpage;topic=28536.0")
soup = BeautifulSoup(f)
b = soup.get_text().encode("utf-8").strip() #the posts contain non-ascii words, so I had to do this
writer = csv.writer(open('silkroad.csv', 'w'))
writer.writerows(b)
【问题讨论】:
我确定您已经知道这一点,但以防万一您不使用 .onion.to 以编程方式访问 .onion 站点可能工作得很好,但您永远不应该像那样浏览它们,因为缺乏安全感。 【参考方案1】:好的,我们开始吧。不太确定我在这里帮助你做什么,但希望你有充分的理由来分析丝绸之路的帖子。
您在这里遇到了一些问题,最大的问题是您根本没有解析数据。 您使用 .get_text() 所做的本质上是转到页面,突出显示整个内容,然后将整个内容复制并粘贴到 csv 文件中。
所以这就是你应该尝试做的事情:
-
阅读页面源码
用汤把它分成你想要的部分
在并行数组中保存作者、日期、时间、帖子等部分
将数据逐行写入 csv 文件
我写了一些代码来向你展示它的样子,它应该可以完成这项工作:
from bs4 import BeautifulSoup
import csv
import urllib2
# get page source and create a BeautifulSoup object based on it
print "Reading page..."
page = urllib2.urlopen("https://silkroad5v7dywlc.onion.to/index.php?action=printpage;topic=28536.0")
soup = BeautifulSoup(page)
# if you look at the html all the titles, dates,
# and authors are stored inside of <dt ...> tags
metaData = soup.find_all("dt")
# likewise the post data is stored
# under <dd ...>
postData = soup.find_all("dd")
# define where we will store info
titles = []
authors = []
times = []
posts = []
# now we iterate through the metaData and parse it
# into titles, authors, and dates
print "Parsing data..."
for html in metaData:
text = BeautifulSoup(str(html).strip()).get_text().encode("utf-8").replace("\n", "") # convert the html to text
titles.append(text.split("Title:")[1].split("Post by:")[0].strip()) # get Title:
authors.append(text.split("Post by:")[1].split(" on ")[0].strip()) # get Post by:
times.append(text.split(" on ")[1].strip()) # get date
# now we go through the actual post data and extract it
for post in postData:
posts.append(BeautifulSoup(str(post)).get_text().encode("utf-8").strip())
# now we write data to csv file
# ***csv files MUST be opened with the 'b' flag***
csvfile = open('silkroad.csv', 'wb')
writer = csv.writer(csvfile)
# create template
writer.writerow(["Time", "Author", "Title", "Post"])
# iterate through and write all the data
for time, author, title, post in zip(times, authors, titles, posts):
writer.writerow([time, author, title, post])
# close file
csvfile.close()
# done
print "Operation completed successfully."
编辑:包含的解决方案可以从目录中读取文件并使用其中的数据
好的,所以您的 HTML 文件位于一个目录中。您需要获取目录中的文件列表,遍历它们,并将目录中的每个文件附加到您的 csv 文件中。
这是我们新程序的基本逻辑。
如果我们有一个名为 processData() 的函数,它将文件路径作为参数并将文件中的数据附加到您的 csv 文件中,如下所示:
# the directory where we have all our HTML files
dir = "myDir"
# our csv file
csvFile = "silkroad.csv"
# insert the column titles to csv
csvfile = open(csvFile, 'wb')
writer = csv.writer(csvfile)
writer.writerow(["Time", "Author", "Title", "Post"])
csvfile.close()
# get a list of files in the directory
fileList = os.listdir(dir)
# define variables we need for status text
totalLen = len(fileList)
count = 1
# iterate through files and read all of them into the csv file
for htmlFile in fileList:
path = os.path.join(dir, htmlFile) # get the file path
processData(path) # process the data in the file
print "Processed '" + path + "'(" + str(count) + "/" + str(totalLen) + ")..." # display status
count = count + 1 # increment counter
碰巧我们的 processData() 函数或多或少与我们之前所做的相同,只是做了一些更改。
所以这与我们上一个程序非常相似,只是有一些小的变化:
-
我们首先编写列标题
在我们打开 csv 并附加 'ab' 标志之后
我们导入 os 来获取文件列表
看起来是这样的:
from bs4 import BeautifulSoup
import csv
import urllib2
import os # added this import to process files/dirs
# ** define our data processing function
def processData( pageFile ):
''' take the data from an html file and append to our csv file '''
f = open(pageFile, "r")
page = f.read()
f.close()
soup = BeautifulSoup(page)
# if you look at the HTML all the titles, dates,
# and authors are stored inside of <dt ...> tags
metaData = soup.find_all("dt")
# likewise the post data is stored
# under <dd ...>
postData = soup.find_all("dd")
# define where we will store info
titles = []
authors = []
times = []
posts = []
# now we iterate through the metaData and parse it
# into titles, authors, and dates
for html in metaData:
text = BeautifulSoup(str(html).strip()).get_text().encode("utf-8").replace("\n", "") # convert the html to text
titles.append(text.split("Title:")[1].split("Post by:")[0].strip()) # get Title:
authors.append(text.split("Post by:")[1].split(" on ")[0].strip()) # get Post by:
times.append(text.split(" on ")[1].strip()) # get date
# now we go through the actual post data and extract it
for post in postData:
posts.append(BeautifulSoup(str(post)).get_text().encode("utf-8").strip())
# now we write data to csv file
# ***csv files MUST be opened with the 'b' flag***
csvfile = open('silkroad.csv', 'ab')
writer = csv.writer(csvfile)
# iterate through and write all the data
for time, author, title, post in zip(times, authors, titles, posts):
writer.writerow([time, author, title, post])
# close file
csvfile.close()
# ** start our process of going through files
# the directory where we have all our HTML files
dir = "myDir"
# our csv file
csvFile = "silkroad.csv"
# insert the column titles to csv
csvfile = open(csvFile, 'wb')
writer = csv.writer(csvfile)
writer.writerow(["Time", "Author", "Title", "Post"])
csvfile.close()
# get a list of files in the directory
fileList = os.listdir(dir)
# define variables we need for status text
totalLen = len(fileList)
count = 1
# iterate through files and read all of them into the csv file
for htmlFile in fileList:
path = os.path.join(dir, htmlFile) # get the file path
processData(path) # process the data in the file
print "Processed '" + path + "'(" + str(count) + "/" + str(totalLen) + ")..." # display status
count = count + 1 # incriment counter
【讨论】:
太棒了!非常感谢你的帮助!别担心,我的意图是好的。 :) 您是否知道如何处理多个本地存储的文件?我知道如何抓取一个文件,但我有一个包含 20k 剥离 HTML 文件的文件夹,就像示例中的那个(每个文件小于 100kb)。 @user3343907 我很高兴它有帮助!至于你的问题,这取决于。如果您有原始 HTML 文档,那应该很容易!而不是从 urllib2 调用定义页面,您只需打开文件并将其读入变量页面。另一方面,如果您使用了原始方法 (.get_text()),它将无法工作,因为您将删除所有允许我们解析不同值的 HTML 标记。 感谢您的回复!是的,我确实有原始文件。我尝试了其中一个,只需以您所说的方式打开它,它就可以完美运行。但是,当我有数千个这样的文件时,逐个文件地手动执行会花费很长时间,所以我希望有更快的方法。 @user3343907 哦,我明白了!肯定有更简单的方法可以做到这一点。我编辑了我的问题以包含一个解决方案,让我知道它是如何工作的!以上是关于BeautifulSoup - 抓取论坛页面的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 beautifulsoup 从 html 页面中抓取纬度/经度数据
BeautifulSoup 不会使用 .find_all('a') 抓取页面中的所有锚标记。我忽略了啥吗?
使用python抓取并分析数据—链家网(requests+BeautifulSoup)(转)
在 python 上使用 selenium 或 beautifulsoup 从带有链接的页面中抓取数据,没有类,没有 id