长话短说,昨天才发现BeautifulSoup,多年来一直没有做任何形式的脚本或编码,在时间紧迫的情况下,乞求帮助。 :)
我的最终目标是使用垂直样式数据表抓取一系列网页并将其拖放到CSV。借助古老的Google,以及今天早些时候我的第一篇关于堆栈溢出的文章(至少十年或以上的第一次),我掌握了基础知识。我可以输入带有URL列表的文本文件,标识包含我需要的表的DIV,刮擦表,以便第一列成为我的标题,第二列成为数据行,并重复下一个URL(不重复标题) )。我遇到的问题是这些页面的代码比我想象的要糟糕得多,其中包括大量额外的行,额外的空格,以及现在我发现的,标签内的嵌套标签,其中大多数是空的。但是,在跨度和多余的行之间,它使到目前为止的脚本忽略了TD内部的某些数据。有关丑陋的页面代码的示例:
<div id="One" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body">
<table class="table table-borderless">
<tbody>
<tr>
<td>ID:</td>
<td>
096626 180012
</td>
</tr>
<tr>
<td>Address:</td>
<td>
1234 Main St
</td>
</tr>
<tr>
<td>Addr City:</td>
<td>
City
</td>
</tr>
<tr>
<td> Name :</td>
<td>
Last name, first name<span> </span>
</td>
</tr>
<tr>
<td>In Care Of Address:</td>
<td>
1234<span> </span>
<span> </span>
Main<span> </span>
St <span> </span>
<span> </span>
<span> </span>
</td>
</tr>
<tr>
<td>City/State/Zip:</td>
<td>
City<span> </span>
ST<span> </span>
Zip<span>-</span>
Zip+4
</td>
</tr>
</tbody>
</table>
</div>
</div>
到目前为止,我的代码是(现在,URL文本文件具有如上所述的本地存储的HTML文件的名称,但是已经用实际的URL进行了测试以验证该部分是否有效):
from bs4 import BeautifulSoup
import requests
import csv
import pandas as pd
contents = []
headers = []
values = []
rows = []
num = 0
with open('sampleurls.txt','r') as csvf:
urls = csv.reader(csvf)
for url in urls:
contents.append(url)
for url in contents:
html = open(url[0]).read()
soup = BeautifulSoup(html, 'html.parser')
trs = soup.select('div#One tr')
for t in trs:
for header, value in zip(t.select('td')[0], t.select('td')[1]):
if num == 0:
headers.append(' '.join(header.split()))
values.append(' '.join(value.split()))
rows.append(values)
values = []
num += 1
df = pd.DataFrame(rows, columns= headers)
print(df.head())
df.to_csv('output5.csv')
执行后,脚本似乎忽略换行符或跨度之后的所有内容,不确定是哪个。我得到的输出是:
,ID:,Address:,Addr City:,Name :,In Care Of Address:,City/State/Zip:
0,096626 180012,1234 Main St,City,"Last name, first name",1234,City
在“收据地址:”列中,我没有得到“ 1234 Main St”,而是得到了“ 1234”。我也尝试了不使用join / split函数的情况,并且地址的其余部分仍然被忽略。有没有解决的办法?从理论上讲,我不需要跨度内的任何数据,因为唯一填充的是zip + 4中的连字符,我不在乎。
请注意,我假设输出中的第一列是CSV编写功能的一部分,但是如果有一种摆脱它的方法,我想这样做。并不是很大,因为当我将CSV导入数据库时我可以忽略它,但是越干净越好。
答案 0 :(得分:0)
在第一位发布正确的信息会更容易..:)
尝试:
from bs4 import BeautifulSoup
import pandas as pd
html = '''
<html>
<body>
<div aria-labelledby="headingOne" class="collapse show" data-parent="#accordionExample" id="One">
<div class="card-body">
<table class="table table-borderless">
<tbody>
<tr>
<td>
ID:
</td>
<td>
096626 180012
</td>
</tr>
<tr>
<td>
Address:
</td>
<td>
1234 Main St
</td>
</tr>
<tr>
<td>
Addr City:
</td>
<td>
City
</td>
</tr>
<tr>
<td>
Name :
</td>
<td>
Last name, first name
<span>
</span>
</td>
</tr>
<tr>
<td>
In Care Of Address:
</td>
<td>
1234
<span>
</span>
<span>
</span>
Main
<span>
</span>
St
<span>
</span>
<span>
</span>
<span>
</span>
</td>
</tr>
<tr>
<td>
City/State/Zip:
</td>
<td>
City
<span>
</span>
ST
<span>
</span>
Zip
<span>
-
</span>
Zip+4
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
'''
contents = []
headers = []
values = []
rows = []
num = 0
soup = BeautifulSoup(html, 'html.parser')
trs = soup.select('div#One tr')
for t in trs:
for header, value in zip(t.select('td')[0], t.select('td:nth-child(2)')):
if num == 0:
headers.append(' '.join(header.split()))
values.append(value.get_text(' ', strip=True))
rows.append(values)
df = pd.DataFrame(rows, columns= headers)
print(df.head())
df.to_csv('output5.csv')
希望它现在可以使用更多相关信息。
csv: