Annuaire d'articles
avant-propos
Je voulais à l'origine mettre à jour scrapy, mais comment puis-je le dire ? Ce n'est pas difficile. En regardant la documentation officielle, vous pouvez le faire. La raison principale est que si votre base de robot n'est pas bonne, vous ne pouvez pas bien jouer à scrapy Et pour la plupart des gens, l'installation de scrapy peut être un problème, car il y a des problèmes historiques, après tout, c'est un ancien framework de python2. Bien sûr, il y a une autre raison. Ce que je veux faire, je ne peux pas utiliser scrapy. Si je peux utiliser scrapy, ce doit être un robot d'exploration distribué, mais ce que je veux faire ici ne peut être qu'un client, c'est-à-dire un logiciel de collection d'araignées, donc ce scrapy ne peut pas être utilisé.
Cible
Ce que nous allons faire aujourd'hui, c'est obtenir la météo, et l'API utilisée est China Weather Network.
BaseUrl = "http://wthrcdn.etouch.cn/weather_mini?city={}"
Il y en a aussi beaucoup en ligne, le crawler qui explore directement le China Weather Network, mais je ne comprends tout simplement pas, pourquoi dois-je aller sur la page Web puis aller sur xpath ou régulier pour le faire, évidemment toutes les données du même api est utilisé, je Pourquoi aller à la page pour inverser l'analyse des données à partir des résultats rendus ? Puis-je simplement obtenir les données directement ?
format de demande
De retour ici, notre interface est une requête get. Ensuite, nous n'avons qu'à mettre la ville ou le numéro dans le champ de la ville, et le résultat de retour est json. Après avoir transformé cette chose en dictionnaire, cela ressemble à ceci
{
'data':
{
'yesterday':
{
'date': '5日星期六', 'high': '高温 16℃', 'fx': '东北风', 'low': '低温 9℃', 'fl': '<![CDATA[3级]]>', 'type': '多云'},
'city': '九江',
'forecast': [{
'date': '6日星期天', 'high': '高温 12℃', 'fengli': '<![CDATA[3级]]>', 'low': '低温 7℃', 'fengxiang': '东北风', 'type': '中雨'},
{
'date': '7日星期一', 'high': '高温 14℃', 'fengli': '<![CDATA[2级]]>', 'low': '低温 7℃', 'fengxiang': '北风', 'type': '多云'},
{
'date': '8日星期二', 'high': '高温 19℃', 'fengli': '<![CDATA[2级]]>', 'low': '低温 8℃', 'fengxiang': '东南风', 'type': '晴'},
{
'date': '9日星期三', 'high': '高温 21℃', 'fengli': '<![CDATA[2级]]>', 'low': '低温 11℃', 'fengxiang': '东南风', 'type': '晴'},
{
'date': '10日星期四', 'high': '高温 23℃', 'fengli': '<![CDATA[1级]]>', 'low': '低温 11℃', 'fengxiang': '南风', 'type': '多云'}
],
'ganmao': '感冒多发期,适当减少外出频率,适量补充水分,适当增减衣物。', 'wendu': '8'}, 'status': 1000, 'desc': 'OK'}
limite de demande
Je dois dire ici que l'interface de China Weather Network yyds n'a aucune restriction. Pourquoi, ce que je veux faire, c'est obtenir des informations météorologiques à travers le pays, y compris les villes de comté, des milliers de villes de comté grandes et petites en Chine, et les analyser par période, de sorte que la visite de demande quotidienne commence au moins 2w. S'il y a une limite, il faut inverser l'anti-escalade, mais grâce à mon test, il n'y a pas de problème.
demande une récupération non asynchrone
Allez, faisons d'abord une comparaison, il n'y a pas de mal sans comparaison, d'accord, car c'est très simple, je vais aller directement au code.
import requests
from datetime import datetime
class GetWeather(object):
urlWheather = "http://wthrcdn.etouch.cn/weather_mini?city={}"
requests = requests
error = {
}
today = datetime.today().day
weekday = datetime.today().weekday()
week = {
0:"星期一",1:"星期二",2:"星期三",3:"星期四",4:"星期五",5:"星期六",6:"星期天"}
def __getday(self)->str:
day = str(self.today)+"日"+self.week.get(self.weekday)
return day
def get_today_wheather(self,city:str)->dict:
data = self.getweather(city)
data = data.get("data").get("forecast")
today = self.__getday()
for today_w in data:
if(today_w.get("date")==today):
return today_w
def getweather(self,city:str,timeout:int=3)->dict:
url = self.urlWheather.format(city)
try:
resp = self.requests.get(url,timeout=timeout)
jsondata = resp.json()
return jsondata
except Exception as e:
self.error['error'] = "天气获取异常"
return self.error
def getweathers(self,citys:list,timeout:int=3):
wheathers_data = {
}
for city in citys:
url = self.urlWheather.format(city)
try:
resp = self.requests.get(url=url,timeout=timeout)
wheather_data = resp.json()
wheathers_data[city]=wheather_data
except Exception as e:
self.error['error'] = "天气获取异常"
return self.error
return wheathers_data
if __name__ == '__main__':
getwheather = GetWeather()
start = time.time()
times = 1
for i in range(5000):
data = getwheather.get_today_wheather("九江")
if((times%100==0)):
print(data,"第",times,"次访问")
times+=1
print("访问",times,"次耗时",time.time()-start,"秒")
Pour ce code, j'ai fait une simple encapsulation.
Voyons les résultats, combien de temps ont duré 5000 visites ?
Ici, j'ai visité la même ville Jiujiang 5000 fois
Extraction asynchrone
Je n'ai pas encapsulé ce code, il a donc l'air désordonné.
Voici quelques points à noter
Limite supérieure du système
Pour cette raison, l'asynchrone est toujours une couche inférieure du système d'exploitation utilisé, donc cette simultanéité a une limite supérieure, car cette coroutine est asynchrone et doit être commutée en permanence, n'est-ce pas ? Cela ressemble un peu au propre multi-threading de python, mais ce "multi-threading" ne basculera que lorsque l'IO sera terminé, sinon il ne basculera pas.
Alors yo, limite-le
codage
import time
import aiohttp
from datetime import datetime
import asyncio
BaseUrl = "http://wthrcdn.etouch.cn/weather_mini?city={}"
WeekIndex = {
0:"星期一",1:"星期二",2:"星期三",3:"星期四",4:"星期五",5:"星期六",6:"星期天"}
today = datetime.today().day
day = str(today)+"日"+WeekIndex.get(datetime.today().weekday())
TIMES = 0
async def request(city:str,semaphore:asyncio.Semaphore,timeout:int = 3):
url = BaseUrl.format(city)
try:
async with semaphore:
async with aiohttp.request("GET", url) as resp:
data = await resp.json(content_type='')
return data
except Exception as e:
raise e
def getwheater(task):
data = task.result()
return data
def get_today_weather(task):
global TIMES
data = task.result() #得到返回结果
data = data.get("data").get("forecast")
for today_w in data:
if (today_w.get("date") == day):
TIMES+=1#只有IO操作的时候才会切换,所以这个++操作还是一个原子性操作
if(TIMES%100==0):
print(today_w,"第",TIMES,"次访问")
return today_w
if __name__ == '__main__':
semaphore = asyncio.Semaphore(500)
#操作系统上限是同一个时刻509/1024个并发,windows509 linux 1024
start = time.time()
tasks = []
for i in range(5000):
c = request("九江",semaphore,3)
task = asyncio.ensure_future(c)
task.add_done_callback(get_today_weather)
tasks.append(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
print("耗时",time.time() - start,"秒")