我在python中编写了一个脚本,用于从网页中抓取分布在多个页面上的某些产品的不同子类别链接,并将这些链接保存在excel文件中的不同表单中(根据产品标题命名)。在这种情况下,我使用了“pyexcel”。首先,刮刀应该比较该网页中“item_list”和“All Brands”的名称。每当找到匹配时,它将抓取该链接,然后跟踪它并解析遍历多个页面的所有子类别链接,并将其保存在excel文件中,如上所述。如果这些产品不分布在多个页面上,它运行时没有任何错误。但是,我在“item_list”中选择了三个“项目”,这些项目已经分页。
当我执行我的脚本时,它会抛出以下错误。但是,我注意到,有了这个错误,一个页面的子类别链接的项目就完成了抓取。在从子类别链接的下一页保存数据时,它会抛出错误。我该如何解决这个问题?提前谢谢。
以下是完整的脚本:
import requests ; from lxml import html
from pyexcel_ods3 import save_data
core_link = "http://store.immediasys.com/brands/"
item_list = ['Adtran','Asus','Axis Communications']
def quotes_scraper(base_link, pro):
response = requests.get(base_link)
tree = html.fromstring(response.text)
data = {}
for titles in tree.cssselect(".SubBrandList a"):
if titles.text == pro:
link = titles.attrib['href']
processing_docs(link, data) #--------#Error thrown here#----- #
def processing_docs(link, data):
response = requests.get(link).text
root = html.fromstring(response)
sheet_name = root.cssselect("#BrandContent h2")[0].text
for item in root.cssselect(".ProductDetails"):
pro_link = item.cssselect("a[class]")[0].attrib['href']
data.setdefault(sheet_name, []).append([str(pro_link)])
save_data("mth.ods", data)
next_page = root.cssselect(".FloatRight a")[0].attrib['href'] if root.cssselect(".FloatRight a") else ""
if next_page:
processing_docs(next_page)
if __name__ == '__main__':
for item in item_list:
quotes_scraper(core_link , item)
我遇到错误:
Traceback (most recent call last):
File "C:\Users\ar\AppData\Local\Programs\Python\Python35-32\goog.py", line 34, in <module>
quotes_scraper(core_link , item)
File "C:\Users\ar\AppData\Local\Programs\Python\Python35-32\goog.py", line 15, in quotes_scraper
processing_docs(link, data)
File "C:\Users\ar\AppData\Local\Programs\Python\Python35-32\goog.py", line 30, in processing_docs
processing_docs(next_page)
TypeError: processing_docs() missing 1 required positional argument: 'data'
顺便说一句,如果我在没有“pyexcel”的情况下运行这个脚本,它根本不会遇到任何问题。我遇到的错误是因为写入和保存数据。
答案 0 :(得分:1)
查看您的代码我认为我可以看到您的问题:
def processing_docs(link, data):
response = requests.get(link).text
root = html.fromstring(response)
sheet_name = root.cssselect("#BrandContent h2")[0].text
for item in root.cssselect(".ProductDetails"):
pro_link = item.cssselect("a[class]")[0].attrib['href']
data.setdefault(sheet_name, []).append([str(pro_link)])
save_data("mth.ods", data)
next_page = root.cssselect(".FloatRight a")[0].attrib['href'] if root.cssselect(".FloatRight a") else ""
if next_page:
processing_docs(next_page) # this line here!
你的函数processing_docs
需要两个参数,但你只用一个递归调用它(processing_docs(next_page)
)。我想你想要递归地将data
字典传递给函数,以便继续添加它? (虽然这可能是错误的 - 一眼就看起来它会保存第1页,然后保存第1页和第2页然后保存第1,2和3页..但我必须仔细观察才能确定)
关于你的第二个问题(在评论中),有几种方法可以做到这一点。
如果我理解您的代码,则使用save_data("mth.ods", data)
保存您的数据 - 如果不是这样,您将项目名称传递给processing_docs
函数:
def processing_docs(link, data, item):
....
save_data(item + ".ods", data)
称之为:
for titles in tree.cssselect(".SubBrandList a"):
if titles.text == pro:
link = titles.attrib['href']
processing_docs(link, data, pro)
和
if next_page:
processing_docs(next_page, data, item)
然后它将为每个项目生成一个新文件,以该项目命名。
你对递归的使用效率稍差 - 我认为它会起作用,因为它会写p1,然后写p1和p2,然后写p1-3,这样你就会得到整个东西(除非数据中存在某些东西)覆盖,但我不这么认为。)
如果不需要继续下一页,可能更好的方法是只保存数据,例如
if next_page:
processing_docs(next_page, data, item)
else:
save_data(item + ".ods", data) # move here and take out elsewhere
你可能需要玩一点才能使它工作,但如果你的数据集很大,它会更快一些。