查看API for the datasets,这可能是最简单的方法。
与此同时,您可以通过以下方式从这些页面获取 id 级别的 API 链接,并将所有包的整个包信息存储在一个列表中,data_sets,以及另一个变量(@ 987654334@)。如果有更好的方法,请务必查看 API 文档 - 例如,如果 id 可以分批提交而不是按 id 提交,那就太好了。
下面的答案是利用文档中详述的端点,该端点用于获取数据集、资源或其他对象的完整 JSON 表示
获取当前登陆页面上的第一个结果:
Guyra 植被 1:25000 地图 VIS_ID 240。
我们想要父级h3 的最后一个子级a,父级具有.dataset-item。在下面,选择器之间的空格是descendant combinators。
.dataset-item h3 a:last-child
您可以将其缩短为 h3 a:last-child,以提高效率。
这种关系可靠地选择页面上的所有相关链接。
继续这个示例,访问检索到的第一个列出项目的 url,我们可以使用 api 端点(检索与此包相关的 json)通过属性=值选择器找到 id,其中包含、*、运算符。我们知道这个特定的 api 端点有一个公共字符串,所以我们在 href 属性值上匹配子字符串:
[href*="/api/3/action/package_show?id="]
域可能会有所不同,并且某些检索到的链接是相对的,因此我们必须测试是否相对并添加适当的域。
该匹配的首页 html:
注意事项:
-
data_sets 是一个包含每个包的所有包数据的列表,并且内容广泛。我这样做是为了让您有兴趣查看这些包中的内容(除了查看 API 文档)
- 您可以通过页面上的汤对象获取总页数
num_pages = int(soup.select('[href^="/data/dataset?page="]')[-2].text)
您可以更改循环以减少页面。
- 会话对象用于efficiency of re-using connection。我敢肯定还有其他改进。特别是我会寻找任何减少请求数量的方法(例如为什么我提到寻找批处理 id 端点)。
- 在返回的包中可以有多个资源 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)