2016-10-10 5 views
0

次のスクリプトを作成して、意図したとおりに動作するAPIエンドポイントから画像をダウンロードしました。それは、すべての要求がお互いに待たなければならないので、むしろ遅いということです。フェッチしたいアイテムごとに同期させることができるようにする正しい方法はありますが、個々のアイテムごとにパラレルにすることは可能です。オンラインサービスからこの servicem8 呼ばそれでは、私が達成したいと考えてすることは次のとおりです。PythonリクエストURLが並行して

  • 可能なすべての仕事を取得し、IDS =>名前を保つ/およびその他の情報
  • 顧客の名前
  • は、各添付ファイルをフェッチフェッチ

この3つの手順は、ジョブごとに実行する必要があります。だから私は、お互いに待つ必要がないので、仕事ごとに物事を並行させることができました。

更新:私は理解していない

問題はあなたがたとえば、私はそうするために並行して物事を行うことができ、その唯一のアイテムごとのように1回の呼び出しで項目ごとに3つのコールをバンドルしていることを確認することができます方法ですたとえば、私はアイテムをフェッチ

  • したいとき(フェッチ名=>フェッチ説明=>フェッチID)

はそうその私は、並列にしたい項目をフェッチ?

私が働くのではなくスローされている現在のコード:

import requests 
import dateutil.parser 
import shutil 
import os 

user = "[email protected]" 
passw = "test" 

print("Read json") 
url = "https://api.servicem8.com/api_1.0/job.json" 
r = requests.get(url, auth=(user, passw)) 

print("finished reading jobs.json file") 
scheduled_jobs = [] 
if r.status_code == 200: 
    for item in r.json(): 
     scheduled_date = item['job_is_scheduled_until_stamp'] 
     try: 
      parsed_date = dateutil.parser.parse(scheduled_date) 
      if parsed_date.year == 2016: 
       if parsed_date.month == 10: 
        if parsed_date.day == 10: 
         url_customer = "https://api.servicem8.com/api_1.0/Company/{}.json".format(item[ 
                            'company_uuid']) 
         c = requests.get(url_customer, auth=(user, passw)) 
         cus_name = c.json()['name'] 
         scheduled_jobs.append(
          [item['uuid'], item['generated_job_id'], cus_name]) 

     except ValueError: 
      pass 

    for job in scheduled_jobs: 
     print("fetch for job {}".format(job)) 
     url = "https://api.servicem8.com/api_1.0/Attachment.json?%24filter=related_object_uuid%20eq%20{}".format(job[ 
                               0]) 
     r = requests.get(url, auth=(user, passw)) 
     if r.json() == []: 
      pass 
     for attachment in r.json(): 
      if attachment['active'] == 1 and attachment['file_type'] != '.pdf': 
       print("fetch for attachment {}".format(attachment)) 
       url_staff = "https://api.servicem8.com/api_1.0/Staff.json?%24filter=uuid%20eq%20{}".format(
        attachment['created_by_staff_uuid']) 
       s = requests.get(url_staff, auth=(user, passw)) 
       for staff in s.json(): 
        tech = "{}_{}".format(staff['first'], staff['last']) 

       url = "https://api.servicem8.com/api_1.0/Attachment/{}.file".format(attachment[ 
                        'uuid']) 
       r = requests.get(url, auth=(user, passw), stream=True) 
       if r.status_code == 200: 
        creation_date = dateutil.parser.parse(
         attachment['timestamp']).strftime("%d.%m.%y") 
        if not os.path.exists(os.getcwd() + "/{}/{}".format(job[2], job[1])): 
         os.makedirs(os.getcwd() + "/{}/{}".format(job[2], job[1])) 
        path = os.getcwd() + "/{}/{}/SC -O {} {}{}".format(
         job[2], job[1], creation_date, tech.upper(), attachment['file_type']) 
        print("writing file to path {}".format(path)) 
        with open(path, 'wb') as f: 
         r.raw.decode_content = True 
         shutil.copyfileobj(r.raw, f) 
else: 
    print(r.text) 

を更新[14/10] 私は与えられたいくつかのヒントを次のようにコードを更新しました。それに感謝します。最適化できるのは、添付ファイルのダウンロードだけですが、今は問題なく動作しています。私が学んだ面白いことは、あなたがWindowsマシン上にCONフォルダを作成できないということです:-)それを知らなかったのです。

私はdictsの私のリストのいくつかのループを避けようとしていますが、私がすでに演奏しているかどうかはわかりません。 Longestは実際には完全なjsonファイルを読み込んでいます。私は完全にAPIの方法を見つけることができなかったので、それらを完全に読んで、2016年9月のジョブだけを返してください。apiクエリ関数はeq/lt/htで動作するようです。

import requests 
import dateutil.parser 
import shutil 
import os 
import pandas as pd 

user = "" 
passw = "" 

FOLDER = os.getcwd() 
headers = {"Accept-Encoding": "gzip, deflate"} 

import grequests 
urls = [ 
    'https://api.servicem8.com/api_1.0/job.json', 
    'https://api.servicem8.com/api_1.0/Attachment.json', 
    'https://api.servicem8.com/api_1.0/Staff.json', 
    'https://api.servicem8.com/api_1.0/Company.json' 
] 

#Create a set of unsent Requests: 

print("Read json files") 
rs = (grequests.get(u, auth=(user, passw), headers=headers) for u in urls) 
#Send them all at the same time: 
jobs,attachments,staffs,companies = grequests.map(rs) 

#create dataframes 
df_jobs = pd.DataFrame(jobs.json()) 
df_attachments = pd.DataFrame(attachments.json()) 
df_staffs = pd.DataFrame(staffs.json()) 
df_companies = pd.DataFrame(companies.json()) 

#url_customer = "https://api.servicem8.com/api_1.0/Company/{}.json".format(item['company_uuid']) 
#c = requests.get(url_customer, auth=(user, passw)) 

#url = "https://api.servicem8.com/api_1.0/job.json" 
#jobs = requests.get(url, auth=(user, passw), headers=headers) 


#print("Reading attachments json") 
#url = "https://api.servicem8.com/api_1.0/Attachment.json" 
#attachments = requests.get(url, auth=(user, passw), headers=headers) 

#print("Reading staff.json") 
#url_staff = "https://api.servicem8.com/api_1.0/Staff.json" 
#staffs = requests.get(url_staff, auth=(user, passw)) 

scheduled_jobs = [] 

if jobs.status_code == 200: 
    print("finished reading json file") 
    for job in jobs.json(): 
     scheduled_date = job['job_is_scheduled_until_stamp'] 
     try: 
      parsed_date = dateutil.parser.parse(scheduled_date) 
      if parsed_date.year == 2016: 
       if parsed_date.month == 9: 
        cus_name = df_companies[df_companies.uuid == job['company_uuid']].iloc[0]['name'].upper() 
        cus_name = cus_name.replace('/', '') 
        scheduled_jobs.append([job['uuid'], job['generated_job_id'], cus_name]) 

     except ValueError: 
      pass 
    print("{} jobs to fetch".format(len(scheduled_jobs))) 

    for job in scheduled_jobs: 
     print("fetch for job attachments {}".format(job)) 
     #url = "https://api.servicem8.com/api_1.0/Attachment.json?%24filter=related_object_uuid%20eq%20{}".format(job[0]) 

     if attachments == []: 
      pass 
     for attachment in attachments.json(): 
      if attachment['related_object_uuid'] == job[0]: 
       if attachment['active'] == 1 and attachment['file_type'] != '.pdf' and attachment['attachment_source'] != 'INVOICE_SIGNOFF': 
        for staff in staffs.json(): 
         if staff['uuid'] == attachment['created_by_staff_uuid']: 
          tech = "{}_{}".format(
           staff['first'].split()[-1].strip(), staff['last']) 

        creation_timestamp = dateutil.parser.parse(
         attachment['timestamp']) 
        creation_date = creation_timestamp.strftime("%d.%m.%y") 
        creation_time = creation_timestamp.strftime("%H_%M_%S") 

        path = FOLDER + "/{}/{}/SC_-O_D{}_T{}_{}{}".format(
         job[2], job[1], creation_date, creation_time, tech.upper(), attachment['file_type']) 

        # fetch attachment 

        if not os.path.isfile(path): 
         url = "https://api.servicem8.com/api_1.0/Attachment/{}.file".format(attachment[ 
                          'uuid']) 
         r = requests.get(url, auth=(user, passw), stream = True) 
         if r.status_code == 200: 
          if not os.path.exists(FOLDER + "/{}/{}".format(job[2], job[1])): 
           os.makedirs(
            FOLDER + "/{}/{}".format(job[2], job[1])) 

          print("writing file to path {}".format(path)) 
          with open(path, 'wb') as f: 
           r.raw.decode_content = True 
           shutil.copyfileobj(r.raw, f) 
        else: 
         print("file already exists") 
else: 
    print(r.text) 
+0

方法の選択に注意してください。これを行うには、ServiceM8 APIのレートが制限されており、同時リクエスト数が多すぎると「HTTP/1.1 429リクエストが多すぎます」 ただし、添付ファイルのリンクを徐々に解決することはできますが、あなたが行く;それらからURLファイルを作成します。ファイルから複数の方法を使って同時にダウンロードすることができます。 'r = requests.get(url、auth =(user、passw)、stream = True)' 'r.url'レスポンスに直接" https:// data-cdn "が含まれています。 servicem8.com/.... "のリンクは、レート制限されません。 – hmedia1

+0

これの効率を大幅に改善する2つの他の簡単な手順: ** 1 **すべてのJob UuidのAttachment APIを呼び出す代わりに、Attachmentsファイル全体を単一の要求で取得し、related_object_uuidあなたが1つのヒットで得た仕事用のuuidsを持っている ** **添付ファイルを正常にダウンロードしたら、ファイルまたはデータベースのどこかに添付ファイルuuidを保存して、uuidがすでに処理されているものはスキップしてください。あなたが添付ファイルダウンローダを実行するたびに、新しい添付ファイルだけをすばやく取得しています。 – hmedia1

+0

.... ....現在の方法では、ファイルが存在するかどうかをテストする前に、すべてのファイルに対してAPIリクエストを実行しています。 – hmedia1

答えて

0

一般的な考え方は、非同期のURL要求を使用することで、ドキュメントからthat- https://github.com/kennethreitz/grequests

ためgrequestsという名前のpythonモジュールがあります:

import grequests 
urls = [ 
    'http://www.heroku.com', 
    'http://python-tablib.org', 
    'http://httpbin.org', 
    'http://python-requests.org', 
    'http://fakedomain/', 
    'http://kennethreitz.com' 
] 
#Create a set of unsent Requests: 
rs = (grequests.get(u) for u in urls) 
#Send them all at the same time: 
grequests.map(rs) 

そしてresopnse

[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, None, <Response [200]>]

+0

私のバージョンからgrequestバージョンへの移行方法をいくつか教えてください。保存するファイルのファイル名を作成するために、他のhttpリクエストの情報が必要です。 – Koen

関連する問題