我试图刮这个网站:voxnews.info
import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor
import pandas as pd
web='https://voxnews.info'
def main(req, num, web):
r = req.get(web+"/page/{}/".format(num))
soup = BeautifulSoup(r.content, 'html.parser')
goal = [(x.time.text, x.h1.a.get_text(strip=True), x.select_one("span.cat-links").get_text(strip=True), x.p.get_text(strip=True))
for x in soup.select("div.site-content")]
return goal
with ThreadPoolExecutor(max_workers=30) as executor:
with requests.Session() as req:
fs = [executor.submit(main, req, num) for num in range(1, 2)] # need to scrape all the webpages in the website
allin = []
for f in fs:
allin.extend(f.result())
df = pd.DataFrame.from_records(
allin, columns=["Date", "Title", "Category", "Content"])
print(df)
但是代码有两个问题:
- 第一个问题是我没有抓取所有的页面(我目前将1和2放在范围内,但我需要所有的页面);
- 它不能正确保存日期。
如果能看看代码,告诉我如何改进它,以解决这两个问题,这将是真棒。
2条答案
按热度按时间2mbi3lxu1#
一些小改动。
首先,对于单个请求,不需要使用requests.Session()--您不需要在请求之间保存数据。
对
with
语句的一个小改动,我不知道它是否更正确,或者只是我的操作方式,你不需要所有的代码在执行器仍然打开的情况下运行。我提供了两种解析日期的方法,一种是按照站点上的写法,一个意大利语字符串,另一种是datetime对象。
我在文章中没有看到任何“p”标记,所以我删除了这部分。似乎为了获得文章的“内容”,你必须实际导航到并逐个抓取它们。我从代码中删除了这一行。
在你的原始代码中,你没有得到页面上的每一篇文章,只是每篇文章的第一篇。每页只有一个“div.site-content”标签,而是多个“article”标签。这就是改变。
最后,我更喜欢查找而不是选择,但这只是我的风格选择。这对我的前三个页面有效,我没有尝试整个网站。当你运行这个时要小心,30个请求中的78个块可能会让你被阻止...
kjthegm62#
为了获取所有页面的结果,而不是一个或十个页面(即硬编码),最好的解决方案是使用一个无限
while
循环,并测试会导致它退出的内容(按钮、元素)。这个解决方案比硬编码的
for
循环更好,因为while
循环将遍历所有页面,无论页面有多少,直到满足某个条件。在我们的示例中,页面上存在一个按钮(.next
CSS选择器):您还可以添加页数限制,一旦达到页数限制,循环也将停止:
检查在线IDE中的代码。
输出示例:
如果你想知道更多关于网站抓取的信息,有一篇13 ways to scrape any public data from any website的博客文章。