这是我之前关于循环浏览多个网页的问题的后续问题。我是编程新手...所以我感谢你的耐心和非常明确的解释!
我已经通过许多网页编写了一个循环。在每个页面上,我想抓取数据,将其保存到变量或csv文件(更容易/更稳定),然后单击" next"按钮,在第二页上刮取数据并将其附加到变量或csv文件等。
具体来说,我的代码如下所示:
url="http://www.url.com"
driver = webdriver.Firefox()
driver.get(url)
(driver.page_source).encode('utf-8')
html = urllib.request.urlopen(url).read()
soup = BeautifulSoup(html)
wait = WebDriverWait(driver, 10)
while True:
# some code to grab the data
job_tag={'class': re.compile("job_title")}
all_jobs=soup.findAll(attrs=job_tag)
jobs=[]
for text in (all_jobs):
t=str(''.join(text.findAll(text=True)).strip())
jobs.append(t)
writer=csv.writer(open('test.csv','a', newline=''))
writer.writerows(jobs)
# click next link
try:
element=wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='reviews']/a/span[starts-with(.,'Next')]")))
element.click()
except TimeoutException:
break
它运行没有错误,但是 1)文件一遍又一遍地收集第一页的数据,但不收集后续页面的数据,即使循环正确执行(最终,我并不介意重复的条目,但我确实需要来自所有页面的数据) )。 我怀疑我需要重新定义"每个新页面的汤,我正在研究如何使bs4访问这些网址。
2)最后一页没有" next"按钮,因此代码不会附加最后一页的数据(当我在csv行中使用'而不是' a'时,我会收到该错误的数据写入csv文件的倒数第二页。
此外,尽管这是一个小问题,但数据在csv中每个单元格写入一个字母,即使我在Python中使用bs4运行该部分时,数据也已正确格式化。我错过了什么?
谢谢!
答案 0 :(得分:0)
我怀疑我需要重新定义"每个新页面的汤
确实,你应该。您看,您的while
循环与soup
一起运行时始终引用您在进入while
循环之前所做的相同旧对象。您应该将soup
重新绑定到新的BeautifulSoup
实例,该实例很可能是您在anchor
(代码a
)后面找到的网址最后一行:
element=wait.until(EC.element_to_be_clickable((By.XPATH, "//*[@id='reviews']/a/span[starts-with(.,'Next')]")))
您可以仅使用soup
访问它(请注意,我没有对此进行测试以确保正确性:没有页面的实际来源,我猜测):
next_link = soup.find(id='reviews').a.get('href')
然后,在while
循环结束时,您将重新绑定soup
:
soup = BeautifulSoup(urllib.request.urlopen(next_link.read()))
你仍然应该添加一个try - except
子句来捕获它在最后一页上找不到的错误,当它找不到最后一个"下一个"链接,然后突破循环。
请注意,selenium
很可能不是您的用例所必需的,bs4
就足够了(但要么会有效)。
此外,尽管这是一个小问题,但数据在csv中每个单元格写入一个字母,即使我在Python中使用bs4运行该部分时,数据也已正确格式化。我错过了什么?
您创建的writer
实例期望其writerows
方法具有可迭代性。你传给它一个字符串(其中可能包含kommas,但那不是csv.writer
所看到的:它会在每两个项目之间添加kommas(或者你在其构造中指定的任何分隔符)可迭代的)。 Python字符串是可迭代的(每个字符),因此writer.writerows("some_string")
不会导致错误。但你很可能想要这个:
for text in (all_jobs):
t = [x.strip() for x in text.find_all(text=True)]
jobs.append(t)
作为评论的后续行动:
您希望根据新网址更新soup
,您可以从1, 2, 3 Next >>
(div
容器中检索到具有特定{{1}的新网址只有id
才能轻松提取。下面的代码是一个相当基本的例子,展示了如何完成。提取相关的内容是由您自己的抓取代码完成的,您必须按照示例中的说明添加这些代码。
BeautifulSoup