2016-12-08 6 views
1

現在、私はCSVにリストされているいくつかのURLをループするために最初のpythonスクリプトを書いています。 14,000以上のリンク私は1)すべてのキーワードタグを取得しようとしています。2)ページのステータスをチェックしてください(404リンクがフラグを立てる必要があります)。 3)youtubeビデオを埋め込みのYouTubeリンクに変換する(ウェブページに移動してキーワードを取得してから埋め込みリンクに変換した後)Python beautifulsoup構文解析の速度向上

これは遅いですが、私はより速い方法を理解できません。私はそれがrequest.get()属性のように感じるが、私はそれをスピードアップできる方法を知らない。私はメタデータだけを必要としますが、それらのすべてではなくページの始めを取得する方法ですか?どのように私はこのコードをより良い/より速く/最適化するのですか?

また、pyinstallerを使用してコンパイルすると、コレクションの問題が発生します。私は、Python 3でのpython 2のコードを使用していますように私は、Python 3.5

import requests 
from bs4 import BeautifulSoup 
import csv 
import re 
import time 

linkLocation = r'C:\Users\JCModern\Desktop\content_links.csv' 
source_code = '' 
myURL = '' 
timestr = time.strftime("%Y%m%d_%H%M%S") 
newfilename = r'C:\Users\JCModern\Desktop\content_links_and_keywords_' + timestr + '.csv' 

with open(newfilename, "w", newline='') as file: 
    writer = csv.writer(file, delimiter=',') 
    writer.writerow(('cmsid', 'filepath', 'metatags', 'pageurl', 'pageurlchange')) 
file.close() 
with open(linkLocation, "r", encoding="utf-8-sig") as f: 
    csv_f = csv.reader(f, delimiter=",") 
    next(csv_f, None) 
    for row in csv_f: 
     if len(row) != 0: 
      # init variables 
      myKeywords = "" 
      myTitle = '' 
      myURL = '' 
      pageUrlChange = '' 
      pageStatus = '' 
      pageUrl = '' 
      myCmsid = (row[0]) 
      myURL = (row[2]) 
      if "https://www.youtube.com/embed/" in myURL: 
       youtubeurl = myURL.split('/') 
       youtubeurl = youtubeurl[4] 
       youtubeurl = re.sub(
        r'\?|\&|\=|re(l=\d+|l)|featur(e=sub|e)|playnext|video(s=\w+|s)|watch|_?((youtu(\.be|be))|fro(m=TL|m)|gdata|player|lis(t=\w+|t)|(inde(x=\w+|x)))_?|(v|vi)=|channel|ytscreeningroom','', youtubeurl) 
       myURL = 'https://www.youtube.com/watch?v=' + youtubeurl 
      try:  
       source_code = requests.get(myURL) 
      except Exception: 
       with open('errors.txt', 'a', newline='') as file: 
        writer = csv.writer(file, delimiter=',') 
        writer.writerow((myCmsid, myURL)) 
       file.close() 
      pageStatus = source_code.status_code 
      plain_text = source_code.text 
      soup = BeautifulSoup(plain_text, 'html.parser') 
      pageStatus = str(pageStatus) 
      pageStatus = pageStatus[:1] 
      pageStatus = int(pageStatus) 
      if pageStatus == 2: 
       pageUrlChange = 0 
      else: 
       pageUrlChange = 1 
      if pageStatus == 3: 
       pageUrl = source_code.url 
      l = soup.findAll("meta", attrs={"name": "keywords"}) 
      if l is None: 
       myKeywords = "" 
      else: 
       try: 
        myKeywords = l[0]['content'] 
       except: 
        myKeywords = myKeywords 
       myKeywords = myKeywords.replace(', ', '~') 
       myKeywords = myKeywords.replace(',', '~') 
       myKeywords = myKeywords.replace('(', '') 
       myKeywords = myKeywords.replace(')', '') 
      if soup.find('title'): 
       myTitle = soup.find('title').string 
      if "https://www.youtube.com/" in myURL: 
       youtubeurl = myURL.split('/') 
       youtubeurl = youtubeurl[3] 
       youtubeurl = re.sub(r'\?|\&|\=|re(l=\d+|l)|featur(e=sub|e)|playnext|video(s=\w+|s)|watch|_?((youtu(\.be|be))|fro(m=TL|m)|gdata|player|lis(t=\w+|t)|(inde(x=\w+|x)))_?|(v|vi)=|channel|ytscreeningroom','', youtubeurl) 
       myURL = 'https://www.youtube.com/embed/' + youtubeurl 
#    print(youtubeurl) 
      if "https://youtu.be/" in myURL: 
       youtubeurl = myURL.split('/') 
       youtubeurl = youtubeurl[3] 
       youtubeurl = re.sub(
        r'\?|\&|\=|re(l=\d+|l)|featur(e=sub|e)|playnext|video(s=\w+|s)|watch|_?((youtu(\.be|be))|fro(m=TL|m)|gdata|player|lis(t=\w+|t)|(inde(x=\w+|x)))_?|(v|vi)=|channel|ytscreeningroom','', youtubeurl) 
       myURL = 'https://www.youtube.com/embed/' + youtubeurl 
#    print(youtubeurl) 
#   print((myCmsid, myURL, myKeywords, pageUrl, pageUrlChange)) 
      with open(newfilename, "a", newline='') as file: 
       writer = csv.writer(file, delimiter=',') 
       writer.writerow((myCmsid, myURL, myKeywords, pageUrl, pageUrlChange)) 
      file.close() 
f.close() 
+0

下記の2つの貴重な回答があります。これは、両方について書く準備をしています。 lxmlとマルチプロセッシング(2つ以上のコアを持っている場合) linecacheモジュールも検討してください。 – marmeladze

答えて

4

html.parserを使用して正規表現を使用して、純粋な-pythonの実装をされて書いていますように私は...感じます。あなたは本当にそれを使用したくないです。単にlxmlをインストールし、代わりにCコードで行わ構文解析持って(その後、BeautifulSoup(plain_text, 'lxml')を使用することを覚えています。

をあなたはまた、あなたのCSVファイルを再開いておく必要はありません。あなたのループの外で、たら、それを開き、あなたのループ内csv.writer()オブジェクトに新しい行を作成します。

あなたはそうではないくらい、URLの読み込みを高速化することはできません。ネットワークの速度は常にボトルネックになるだろう。あなたは非常に低レベルPyCurl libraryを使用することができ、しかし、私が提供できるスピードアップがここに影響を与えるだろうとは思わない。

1

高速なxmlパーサに移行するという優れた提案に加えて、これはmultiprocessingモジュールを介した並列化に適した候補です。私はあなたのコードをサブプロセスに委譲できるワーカーで要求/解析を行うように並べ替えました。ワーカーはcsvに追加する必要がある行を返します。返された行の先頭に0/-1のエラーコードを追加したので、親プロセスはどのcsvが結果を得ているか知っています。

import requests 
from bs4 import BeautifulSoup 
import csv 
import re 
import time 
import multiprocessing 
import traceback 

def grabber(myCmsid, myURL): 
    try: 
     return grabber_impl(myCmsid, myURL) 
    except: 
     return (-1, myCmsid, myURL, traceback.format_exc()) 

def grabber_impl(myCmsid, myURL): 
    # init variables 
    myKeywords = "" 
    myTitle = '' 
    myURL = '' 
    pageUrlChange = '' 
    pageStatus = '' 
    pageUrl = '' 
    if "https://www.youtube.com/embed/" in myURL: 
     youtubeurl = myURL.split('/') 
     youtubeurl = youtubeurl[4] 
     youtubeurl = re.sub(
      r'\?|\&|\=|re(l=\d+|l)|featur(e=sub|e)|playnext|video(s=\w+|s)|watch|_?((youtu(\.be|be))|fro(m=TL|m)|gdata|player|lis(t=\w+|t)|(inde(x=\w+|x)))_?|(v|vi)=|channel|ytscreeningroom','', youtubeurl) 
     myURL = 'https://www.youtube.com/watch?v=' + youtubeurl 

    source_code = requests.get(myURL) 
    pageStatus = source_code.status_code 
    plain_text = source_code.text 
    soup = BeautifulSoup(plain_text, 'html.parser') 
    pageStatus = str(pageStatus) 
    pageStatus = pageStatus[:1] 
    pageStatus = int(pageStatus) 
    if pageStatus == 2: 
     pageUrlChange = 0 
    else: 
     pageUrlChange = 1 
    if pageStatus == 3: 
     pageUrl = source_code.url 
    l = soup.findAll("meta", attrs={"name": "keywords"}) 
    if l is None: 
     myKeywords = "" 
    else: 
     try: 
      myKeywords = l[0]['content'] 
     except: 
      myKeywords = myKeywords 
     myKeywords = myKeywords.replace(', ', '~') 
     myKeywords = myKeywords.replace(',', '~') 
     myKeywords = myKeywords.replace('(', '') 
     myKeywords = myKeywords.replace(')', '') 
    if soup.find('title'): 
     myTitle = soup.find('title').string 
    if "https://www.youtube.com/" in myURL: 
     youtubeurl = myURL.split('/') 
     youtubeurl = youtubeurl[3] 
     youtubeurl = re.sub(r'\?|\&|\=|re(l=\d+|l)|featur(e=sub|e)|playnext|video(s=\w+|s)|watch|_?((youtu(\.be|be))|fro(m=TL|m)|gdata|player|lis(t=\w+|t)|(inde(x=\w+|x)))_?|(v|vi)=|channel|ytscreeningroom','', youtubeurl) 
     myURL = 'https://www.youtube.com/embed/' + youtubeurl 
#    print(youtubeurl) 
    if "https://youtu.be/" in myURL: 
     youtubeurl = myURL.split('/') 
     youtubeurl = youtubeurl[3] 
     youtubeurl = re.sub(
      r'\?|\&|\=|re(l=\d+|l)|featur(e=sub|e)|playnext|video(s=\w+|s)|watch|_?((youtu(\.be|be))|fro(m=TL|m)|gdata|player|lis(t=\w+|t)|(inde(x=\w+|x)))_?|(v|vi)=|channel|ytscreeningroom','', youtubeurl) 
     myURL = 'https://www.youtube.com/embed/' + youtubeurl 
#    print(youtubeurl) 
#   print((myCmsid, myURL, myKeywords, pageUrl, pageUrlChange)) 
    return (0, myCmsid, myURL, myKeywords, pageUrl, pageUrlChange)) 


linkLocation = r'C:\Users\JCModern\Desktop\content_links.csv' 
source_code = '' 
myURL = '' 
timestr = time.strftime("%Y%m%d_%H%M%S") 
newfilename = r'C:\Users\JCModern\Desktop\content_links_and_keywords_' + timestr + '.csv' 

with open(linkLocation, "r", encoding="utf-8-sig") as f: 
    csv_f = csv.reader(f, delimiter=",") 
    next(csv_f, None) 
    pool = multiprocessing.Pool() 

    with open(newfilename, 'a', newline='') as out, open('errors.txt', 'a', newline='') as err: 
     writer = csv.writer(out, delimiter=',') 
     err_writer = csv.writer(err, delimiter=',') 
     for result in pool.imap_unordered(grabber, ((row[0], row[2]) for row in csv_f if row), chunksize=1): 
      if result[0]: 
       writer.writerow(result[1:]) 
      else: 
       print(result[3]) 
       err_writer.writerow(result[1:3]) 
pool.close() 
pool.join() 
+0

私は返信を感謝しますが、このコードは実際に何もしないようです。私はそれを15分間実行したままにしましたが、error.txtファイルが作成されましたが、何もありません。content_links_and_keywords_date.csvファイルが作成されましたが、何もありません。私は "print((myCmsid、myURL、myKeywords、pageUrl、pageUrlChange))"のコメントを外して返しません。 –

+0

例外ハンドラがワーカ全体をカバーするようにサンプルを更新しました。 'Pool.imap_unordered'は親のexecptionsを返すでしょう、おそらくそれはあなたの問題でした。私はあなたがより良いhtmlパーサのコードを変更しようとしているのを見ました...良いアイデア!しかしおそらく最高の問題でした...この変更はちょうど実例でした - 私はそれを実行することができないので、私はそれをテストすることはできません。 1つの選択肢は、私たちがすべて実行できるもっと短い例です。 – tdelaney

関連する問題