gpt4 book ai didi

python - 如何抓取嵌入的链接和表格信息

转载 作者:行者123 更新时间:2023-12-01 07:47:22 24 4
gpt4 key购买 nike

我正在尝试抓取 this website 上可用数据集的信息.

我想收集资源的 URL 以及至少数据集的标题。

使用this resource例如,我想捕获“转到资源”中嵌入的 URL 以及表中列出的标题: enter image description here

我已经创建了一个基本的抓取工具,但它似乎不起作用:

import requests
import csv
from bs4 import BeautifulSoup

site = requests.get('https://data.nsw.gov.au/data/dataset');
data_list=[]

if site.status_code is 200:
content = BeautifulSoup(site.content, 'html.parser')
internals = content.select('.resource-url-analytics')
for url in internals:
title = internals.select=('.resource-url-analytics')[0].get_text()
link = internals.select=('.resource-url-analytics')[0].get('href')
new_data = {"title": title, "link": link}
data_list.append(new_data)
with open ('selector.csv','w') as file:
writer = csv.DictWriter(file, fieldnames = ["dataset", "link"], delimiter = ';')
writer.writeheader()
for row in data_list:
writer.writerow(row)

我想将输出写入 CSV,其中包含 URL 和标题列。

这是所需输出的示例

Desired output table

非常感谢您的帮助

最佳答案

看看 API for the datasets这可能是最简单的方法。

同时,您可以通过以下方法从这些页面获取 ID 级别的 API 链接,并将所有包的完整包信息存储在一个列表 data_sets 中,并且仅存储感兴趣的信息在另一个变量中(结果)。请务必查看 API 文档,以防有更好的方法 - 例如,如果可以批量提交 id,而不是按 id 提交,那就太好了。

下面的答案是利用文档中详细说明的端点,该端点用于获取数据集、资源或其他对象的完整 JSON 表示形式

获取着陆页上当前的第一个结果:

Guyra 植被 1:25000 map VIS_ID 240

我们希望父级 h3 的最后一个子级 a 具有类 .dataset-item 的父级。在下面,选择器之间的空格是 descendant combinators .

.dataset-item h3 a:last-child

您可以将其缩短为 h3 a:last-child 以获得较小的效率提升。

这种关系可靠地选择页面上的所有相关链接。

enter image description here

继续这个示例,访问第一个列出的项目的检索 url,我们可以使用 api 端点(检索与此包相关的 json)通过包含、*、运算符的 attribute=value 选择器找到 id。我们知道这个特定的 api 端点有一个公共(public)字符串,因此我们对 href 属性值进行子字符串匹配:

[href*="/api/3/action/package_show?id="]

域名可能会有所不同,并且某些检索到的链接是相对的,因此我们必须测试是否相对并添加适当的域名。

该比赛的首页 html:

enter image description here

<小时/>

注释:

  1. data_sets 是一个包含每个包的所有包数据的列表,内容很广泛。我这样做是为了防止您有兴趣查看这些包中的内容(除了查看 API 文档之外)
  2. 您可以通过以下方式从页面上的 soup 对象获取总页数

   num_pages = int(soup.select('[href^="/data/dataset?page="]')[-2].text)

您可以更改更少页面的循环。

  1. Session 对象用于efficiency of re-using connection 。我确信还有其他方面需要改进。特别是,我会寻找任何减少请求数量的方法(例如为什么我提到寻找批处理 ID 端点)。
  2. 返回的包中不能有一个或多个资源 URL。参见示例here 。您可以编辑代码来处理此问题。
<小时/>

Python:

from bs4 import BeautifulSoup as bs
import requests
import csv
from urllib.parse import urlparse

json_api_links = []
data_sets = []

def get_links(s, url, css_selector):
r = s.get(url)
soup = bs(r.content, 'lxml')
base = '{uri.scheme}://{uri.netloc}'.format(uri=urlparse(url))
links = [base + item['href'] if item['href'][0] == '/' else item['href'] for item in soup.select(css_selector)]
return links

results = []
#debug = []
with requests.Session() as s:

for page in range(1,2): #you decide how many pages to loop

links = get_links(s, 'https://data.nsw.gov.au/data/dataset?page={}'.format(page), '.dataset-item h3 a:last-child')

for link in links:
data = get_links(s, link, '[href*="/api/3/action/package_show?id="]')
json_api_links.append(data)
#debug.append((link, data))
resources = list(set([item.replace('opendata','') for sublist in json_api_links for item in sublist])) #can just leave as set

for link in resources:
try:
r = s.get(link).json() #entire package info
data_sets.append(r)
title = r['result']['title'] #certain items

if 'resources' in r['result']:
urls = ' , '.join([item['url'] for item in r['result']['resources']])
else:
urls = 'N/A'
except:
title = 'N/A'
urls = 'N/A'
results.append((title, urls))

with open('data.csv','w', newline='') as f:
w = csv.writer(f)
w.writerow(['Title','Resource Url'])
for row in results:
w.writerow(row)
<小时/>

所有页面

(运行时间非常长,因此请考虑线程/异步):

from bs4 import BeautifulSoup as bs
import requests
import csv
from urllib.parse import urlparse

json_api_links = []
data_sets = []

def get_links(s, url, css_selector):
r = s.get(url)
soup = bs(r.content, 'lxml')
base = '{uri.scheme}://{uri.netloc}'.format(uri=urlparse(url))
links = [base + item['href'] if item['href'][0] == '/' else item['href'] for item in soup.select(css_selector)]
return links

results = []
#debug = []

with requests.Session() as s:
r = s.get('https://data.nsw.gov.au/data/dataset')
soup = bs(r.content, 'lxml')
num_pages = int(soup.select('[href^="/data/dataset?page="]')[-2].text)
links = [item['href'] for item in soup.select('.dataset-item h3 a:last-child')]

for link in links:
data = get_links(s, link, '[href*="/api/3/action/package_show?id="]')
json_api_links.append(data)
#debug.append((link, data))
if num_pages > 1:
for page in range(1, num_pages + 1): #you decide how many pages to loop

links = get_links(s, 'https://data.nsw.gov.au/data/dataset?page={}'.format(page), '.dataset-item h3 a:last-child')

for link in links:
data = get_links(s, link, '[href*="/api/3/action/package_show?id="]')
json_api_links.append(data)
#debug.append((link, data))

resources = list(set([item.replace('opendata','') for sublist in json_api_links for item in sublist])) #can just leave as set

for link in resources:
try:
r = s.get(link).json() #entire package info
data_sets.append(r)
title = r['result']['title'] #certain items

if 'resources' in r['result']:
urls = ' , '.join([item['url'] for item in r['result']['resources']])
else:
urls = 'N/A'
except:
title = 'N/A'
urls = 'N/A'
results.append((title, urls))

with open('data.csv','w', newline='') as f:
w = csv.writer(f)
w.writerow(['Title','Resource Url'])
for row in results:
w.writerow(row)

关于python - 如何抓取嵌入的链接和表格信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56406039/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com