我写了一些目前正在运行的网页抓取代码,但是速度很慢。背景知识:我正在使用Selenium,因为它需要多个阶段的单击和输入以及BeautifulSoup。我的代码正在查看网站上子类别中的材料列表(下图),然后抓取它们。如果从网站上刮取的材料是我感兴趣的30种材料之一(下面第一条),则它将数字1写入数据框,然后将其转换为Excel工作表。
无论如何,我认为它之所以如此缓慢的原因是由于存在许多例外。但是,除了try / except之外,我不确定如何处理这些问题。代码的主要部分可以在下面看到,因为整个代码很长。我还附上了该网站的图片以供参考。
lst = ["Household cleaner and detergent bottles", "Plastic milk bottles", "Toiletries and shampoo bottles", "Plastic drinks bottles",
"Drinks cans", "Food tins", "Metal lids from glass jars", "Aerosols",
"Food pots and tubs", "Margarine tubs", "Plastic trays","Yoghurt pots", "Carrier bags",
"Aluminium foil", "Foil trays",
"Cardboard sleeves", "Cardboard egg boxes", "Cardboard fruit and veg punnets", "Cereal boxes", "Corrugated cardboard", "Toilet roll tubes", "Food and drink cartons",
"Newspapers", "Window envelopes", "Magazines", "Junk mail", "Brown envelopes", "Shredded paper", "Yellow Pages" , "Telephone directories",
"Glass bottles and jars"]
def site_scraper(site):
page_loc = ('//*[@id="wrap-rlw"]/div/div[2]/div/div/div/div[2]/div/ol/li[{}]/div').format(site)
page = driver.find_element_by_xpath(page_loc)
page.click()
driver.execute_script("arguments[0].scrollIntoView(true);", page)
soup=BeautifulSoup(driver.page_source, 'lxml')
for i in x:
for j in y:
try:
material = soup.find_all("div", class_ = "rlw-accordion-content")[i].find_all('li')[j].get_text(strip=True).encode('utf-8')
if material in lst:
df.at[code_no, material] = 1
else:
continue
continue
except IndexError:
continue
x = xrange(0,8)
y = xrange(0,9)
p = xrange(1,31)
for site in p:
site_scraper(site)
具体来说,i和j很少达到6,7或8,但是当它们达到时,也必须捕获该信息也很重要。就上下文而言,i对应于下图中的不同类别的数量(汽车,建筑材料等),而j代表子列表(汽车电池和机油等)。因为每个代码的所有30个站点都重复了这两个循环,而我有1500个代码,所以这非常慢。目前,使用10个代码需要6.5分钟。
有没有办法可以改善这个过程?我尝试了列表理解,但是很难处理这样的错误,并且我的结果不再准确。 “ if”函数可能是一个更好的选择吗?如果是,我将如何合并呢?如果需要,我也很乐意附加完整的代码。谢谢!
编辑: 通过更改
except IndexError:
continue
到
except IndexError:
break
现在它的运行速度几乎快一倍!显然,最好在失败一次后退出循环,因为以后的迭代也会失败。但是,仍然欢迎其他任何pythonic技巧:)
答案 0 :(得分:0)
听起来您只需要这些lis
的文本:
lis = driver.execute_script("[...document.querySelectorAll('.rlw-accordion-content li')].map(li => li.innerText.trim())")
现在,您可以将其用于逻辑:
for material in lis:
if material in lst:
df.at[code_no, material] = 1