Python 搜索和抓取
Python Search and Scrape
我有一个问题,我想知道是否值得花时间尝试用 Python 来解决。我有一个很大的鱼类学名 CSV 文件。我想将该 CSV 文件与大型鱼类形态信息数据库 (www.fishbase.ca) 进行交叉引用,并将代码 return 设为每条鱼的最大长度。基本上,我需要创建代码来搜索 fishbase 网站上的每条鱼,然后在页面上找到最大长度信息,然后 return 在 CSV 文件中给我。最后两部分相对简单,但第一部分是我卡住的地方。提前致谢。
因此,为了在其他 Web 应用程序中使用这些信息,您需要使用 API 来获取他们的数据。
Fishbase.ca(或 .org)没有面向 public 的官方 API。有一些 chat in 2013 关于创建 RESTful API 这将是您需要的门票,但这还没有发生(不要屏住呼吸)。
另一种方法是使用您需要查找的鱼的名称,将其放入 URI(例如 www.fishbase.ca/fish/Rainbow+Trout),然后使用 Xquery 或类似工具向下钻取DOM求最大长度。
不幸的是,fishbase 也没有此方法所需的那种 URI,this 是虹鳟鱼的 URI - 使用 ID 而不是名称来轻松查找。
我建议寻找另一个数据提供者来寻找这两个 API 中的任何一个。
关于第二种方法:网站所有者可能不喜欢您以这种方式使用他们的网站。如果可以,请事先询问他们。
看起来你可以直接从属和种生成 url,即
虹鳟 (oncorhynchus mykiss) 变成
http://www.fishbase.ca/summary/Oncorhynchus-mykiss.html
类似
def make_url(genus, species):
return (
"http://www.fishbase.ca/summary/{}-{}.html"
.format(genus.title(), species.lower())
)
查看页面源代码,html 严重不符合语义;虽然用正则表达式解析 html 是邪恶和可怕的,但我真的认为这是这种情况下最简单的方法:
import re
fishlength = re.compile("max length : ([\d.]+) ([cm]{1,2})", re.I).search
def get_length_in_cm(html):
m = fishlength(html)
if m: # match found
value = float(m.group(1))
unit = m.group(2)
if unit == "cm":
return value
elif unit == "m":
return value * 100.
else:
raise ValueError("Unknown unit: {}".format(unit))
else:
raise ValueError("Length not found")
然后抓取每一页,
import csv
import requests
from time import sleep
DELAY = 2
GENUS_COL = 4
SPECIES_COL = 5
with open("fish.csv") as inf:
next(inf) # skip header row
for row in csv.reader(inf):
url = make_url(row[GENUS_COL], row[SPECIES_COL])
# should add error handling, in case
# that page doesn't exist
html = requests.get(url).text
length = get_length_in_cm(html)
# now store the length value somewhere
# be nice, don't pound their site
sleep(DELAY)
我有一个问题,我想知道是否值得花时间尝试用 Python 来解决。我有一个很大的鱼类学名 CSV 文件。我想将该 CSV 文件与大型鱼类形态信息数据库 (www.fishbase.ca) 进行交叉引用,并将代码 return 设为每条鱼的最大长度。基本上,我需要创建代码来搜索 fishbase 网站上的每条鱼,然后在页面上找到最大长度信息,然后 return 在 CSV 文件中给我。最后两部分相对简单,但第一部分是我卡住的地方。提前致谢。
因此,为了在其他 Web 应用程序中使用这些信息,您需要使用 API 来获取他们的数据。
Fishbase.ca(或 .org)没有面向 public 的官方 API。有一些 chat in 2013 关于创建 RESTful API 这将是您需要的门票,但这还没有发生(不要屏住呼吸)。
另一种方法是使用您需要查找的鱼的名称,将其放入 URI(例如 www.fishbase.ca/fish/Rainbow+Trout),然后使用 Xquery 或类似工具向下钻取DOM求最大长度。
不幸的是,fishbase 也没有此方法所需的那种 URI,this 是虹鳟鱼的 URI - 使用 ID 而不是名称来轻松查找。
我建议寻找另一个数据提供者来寻找这两个 API 中的任何一个。
关于第二种方法:网站所有者可能不喜欢您以这种方式使用他们的网站。如果可以,请事先询问他们。
看起来你可以直接从属和种生成 url,即
虹鳟 (oncorhynchus mykiss) 变成
http://www.fishbase.ca/summary/Oncorhynchus-mykiss.html
类似
def make_url(genus, species):
return (
"http://www.fishbase.ca/summary/{}-{}.html"
.format(genus.title(), species.lower())
)
查看页面源代码,html 严重不符合语义;虽然用正则表达式解析 html 是邪恶和可怕的,但我真的认为这是这种情况下最简单的方法:
import re
fishlength = re.compile("max length : ([\d.]+) ([cm]{1,2})", re.I).search
def get_length_in_cm(html):
m = fishlength(html)
if m: # match found
value = float(m.group(1))
unit = m.group(2)
if unit == "cm":
return value
elif unit == "m":
return value * 100.
else:
raise ValueError("Unknown unit: {}".format(unit))
else:
raise ValueError("Length not found")
然后抓取每一页,
import csv
import requests
from time import sleep
DELAY = 2
GENUS_COL = 4
SPECIES_COL = 5
with open("fish.csv") as inf:
next(inf) # skip header row
for row in csv.reader(inf):
url = make_url(row[GENUS_COL], row[SPECIES_COL])
# should add error handling, in case
# that page doesn't exist
html = requests.get(url).text
length = get_length_in_cm(html)
# now store the length value somewhere
# be nice, don't pound their site
sleep(DELAY)