我正在抓取一个网站,以便将数据存储在一个包含3列的数据库中。我正在抓取的网站部分看起来像下面三个例子中的任何一个
# Example 1:
<div>
<a href="sample1">text1</a>
</div>
# Example 2:
<div>
<a href="sample1">text1</a>
<a href="sample2">text2</a>
</div>
# Example 3:
<div>
<a href="sample1">text1</a>
<a href="sample2">text2</a>
<a href="sample3">text3</a>
</div>
我正在尝试分配
这样做的最佳方法是什么?
我尝试过的一些事情是
### FIRST ATTEMPT
var1, var2, var3 = '','',''
# could also do var1, var2, var3 = ('',)*3
all = soup.find_all('a')
var1 = all[0].text
try:
var2 = all[1].text
except:
pass
try:
var3 = all[3].text
except:
pass
#### SECOND ATTEMPT
all = [s.text for s in soup.find_all('a')]
# This is where i get stuck... This could return a list of length 1, 2, or 3, and I need the output to be a list of length 3 so i can use the following line to assign variables
var1, var2, var3 = all
#### THIRD ATTEMPT
all = [s.text for s in soup.find_all('a')]
var1, var2, var3 = '','',''
n = len(all)
var1 = all[0].text
if n = 2:
var2 = all[1].text
else:
var2 = all[1].text
var3 = all[2].text
编辑: 我试图在我的数据库中有三个字段的原因是因为我希望能够按这些不同的变量进行过滤。 var1是最准确的标签,var2稍微准确一些,var3在高水平上是准确的。把它想象成衣服...... var1可能是宽松的裤子,var2可能是商务休闲裤,var3可能是裤子。
答案 0 :(得分:2)
您可以使用一些简单的列表乘法:
# use a constant at the top of your script in case the number of columns
# change in the future
COLUMNS = 3
# ... other code ...
all = [s.text for s in soup.find_all('a')]
all.extend(['']*(COLUMNS-len(all))) # append 1 empty string for each missing text field
var1, var2, var3 = all
但正如David Zemens在评论中提到的那样,必须有更好的方法来做到这一点。如果没有看到消耗文本变量的代码,我就无法提出任何具体建议,但您应该认真重新考虑您的设计。即使您像我建议的那样使用常量,但var1, var2, var3 = all
仍然会在将来难以维护和修改此脚本。
根据你的编辑,我建议你改用字典。这将允许您按名称引用特定数据,就像引用变量一样,但保留了列表的灵活性,而不是限制您使用硬编码的变量数。
例如:
all = [s.text for s in soup.find_all('a')]
d = {}
for i, field in enumerate(all):
d['var{}'.format(i)] = field
# later in your code that consumes this dictionary...
try:
foo(d['var1']) # function to do something with the scraped string corresponding
# to var1
except KeyError:
# do something else or pass when the expected data doesn't exist
如果all
为['a', 'b']
,则此代码会生成以下内容:
{'var1':'b','var0':'a'}
变量赋值实际上只不过是一个映射 - 您的代码知道变量名称,它可以查找相应的值。字典允许您的代码动态构建映射,而不是您必须对其进行硬编码。现在我们已经构建了一个字典,其中varX
变量是动态构造的。如果您决定添加另一列,则无需更改此代码。您只需添加使用var4
的代码,并准备好在字典中不存在var4
时捕获异常。不再添加空字符串 - 您的代码已准备好处理它所查找的数据不存在的情况。
注意:
enumerate()
函数遍历可迭代对象并为您递增计数器。在我的代码中,i
是计数器(因此我们可以构造'var1','var2'...字符串),field
是列表中的每个项目。答案 1 :(得分:2)
你的第二次尝试可能更加pythonic。当然,您事先并不知道.find_all
的结果是否为长度== 3(或更多或更少)的列表。因此,您应该使用try / except或其他逻辑来控制结果写入数据库的方式/时间。
# create a dictionary of your database column names:
dbColumns = {0:'column1', 1:'column2', 2:'column3'}
# get all the results; there might be 0 or 3 or any number really,
# we'll deal with that later
results = [s.text if s.text else "" for s in soup.find_all('a')]
# iterate the items in the list, and put in corresponding DB
for col in range(len(results)):
# use the dbColumns dict to insert to the desired column
query = "Insert INTO [db_name].[" + dbColumns[col] + "]"
query += "VALUES '" + results[i] + '"
"""
db.insert(query) # assumes a db object that has an "insert" function; modify as needed
"""
这种方法的意义在于,似乎没有任何关于这个问题的技术上需要对三个对象(var1,var2,var3)进行硬编码并试图分配给它们。相反,只需返回find_all
的结果,并通过其结果列表中的索引处理它们。
答案 2 :(得分:1)
怎么样:
all = soup.find_all('a')
var1 = all[0].text if len(all) > 0 else ""
var2 = all[1].text if len(all) > 1 else ""
var3 = all[2].text if len(all) > 2 else ""
条件表达式x if y else z
(通常称为三元运算符)使代码简单易读。但它不会赢得任何设计奖。
答案 3 :(得分:0)
您可以尝试
#if list1 has uncertain number of values and you want to give them each variable
#create random list2 with max number of possible veriables
list2 = ['var1', 'var2', 'var3', 'var4' , . . . ]
for li1, li2 in zip(list1, list2):
globals()[li2] = li1
print(li2)
我不是python专家,我只是靠自己想出了一点,可能不是pythonic,但是可以解决问题