39011
pythonでwebアプリを作りながら勉強しているのですが、importの仕組みがよくわからないです。  
importを使えば別の.pyの中にある変数も持ってこれるのでしょうか？

```

    ■検索エンジン
    |---■config.py
    |---■manage.py
    |---■web_crawler
    　　|---■\__init__.py
    　　|---■crawler.py
    　　|---■drop_collection.py
    |---■search_engine
    　　|---■\__init__.py
    　　|---■template
    　　　　|---■index.html
    
```

フォルダ構成はこのようになっていて  
今はdrop_collection.pyを実行してDBのコレクションを削除したいのですが

**エラー**  
from config import MONGO_URL  
ImportError: No module named 'config'

表示されて実行出来ないです。

元々はcrawler.pyからimportしたCollectionを使って

```

    Collection(Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'test'), 'Index')
    
```

DBのコレクションを削除するプログラムだったんですけど、それが動かなくて自分で書き換えてみたのですが動きませんでした。

**変更前drop_collection.pyの中身です。**

```

    # -*- coding: utf-8 -*-
    __author__ = 'masashi'
    #web_crawlerからDBのデータを持ってくるそしてcolの中にしまっとく。
    from web_crawler import collection as col
    
    
    def drop_collection():
        col.drop()
    
    if __name__ == '__main__':
        drop_collection()
    
```

crawler.pyはしっかり動作するので

```

    from config import MONGO_URL
    
```

を使ってDBのデータを持ってこれると思い以下のように書いたのですが同じエラーがでました。  
pythonの対話から直接from config import MONGO_URLを行っても同じエラーが出たのでどうしていいかわかりません。  
crawler.pyはmanage.pyを実行して動かすのですが、それと関係があるでしょうか？  
検索エンジンのフォルダからpython対話に入ってfrom config import MONGO_URLを実行したらエラーが出ませんでした。  
階層が関係あるみたいというのはわかりました。  
ですが、プログラムをどのように書いたらいいのかわかりません。  
詳しい方回答いただけないでしょうか？

**変更後drop_collection.pyの中身です。**

configのパスを変更したのですが新しいエラーが出てきました。  
configが現在のディレクトリないのが問題だと返信を頂いたのですが、crawler.pyではconfigをうまく読み込めるます。それはどうしてなのでしょうか？

**追記エラー**  
from ..config import MONGO_URL  
SystemError: Parent module '' not loaded, cannot perform relative import

```

    # -*- coding: utf-8 -*-
    
    #これを直接実行するとDBの中身が削除される。
    
    
    #help()でやると作った人の名前で出る。
    
    __author__ = 'Wataru'
    
    
    from urllib.parse import urlparse
    from pymongo import MongoClient
    from ..config import MONGO_URL
    
    
    client = MongoClient(MONGO_URL)
    db = client[urlparse(MONGO_URL).path[1:]]
    col = db["Index"]
    
    def drop_collection():
        #作成したDBのコレクションを削除する。    
        col.drop()
    
    #if__name__ == '__main__'はこれが直接実行されたものなのか(python drop_collection.py)チェックしてもしそうなら
    #drop_collectionを実行する。
    if __name__ == '__main__':
        drop_collection()
    
```

**config.pyの中身**

```

    import os
    
    #接続先のホストはデフォルトだと ‘localhost’ でポート番号は 27017
    # application settings
    #os.environ.get('MONGO_URL')通常のサーバーにアプリをあげるならこのようにしてURLを持ってくる必要があると思う。
    MONGO_URL = 'mongodb://localhost:27017/test'
    
    # Generate a random secret key
    SECRET_KEY = os.urandom(24)
    #セキュリティについての設定だけどxssとcsrfというのがあるらしい（多分使われてないけど聞く必要がある）
    #flaskのconfig設定だと思ったけど違った。
    CSRF_ENABLED = True
    
```

**crawler.pyの中身**

```

    # -*- coding: utf-8 -*-
    
    #pythonの標準のモジュールでurlからhtmlのファイルを持って来てくれる。
    import requests
    #pythonの標準のモジュールでurlの解析をしてくれる。
    from urllib.parse import urlparse
    #mongodbを操作する時に使用するモジュールでMongoClientでDBに接続する。
    from pymongo import MongoClient
    #日本語形態のやつを解析できる。
    from janome.tokenizer import Tokenizer
    #htmlからリンクを抜き出してくれる。
    from bs4 import BeautifulSoup
    #config.pyからMONGO_URLを持ってくる。
    from config import MONGO_URL
    
    #DBに接続
    #print(MONGO_URL) mongodb://localhost:27017/test
    
    client = MongoClient(MONGO_URL)
    #urlparseでURLのパスだけ抜き出す。それでデータベースを取得
    #print(client) MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True)
    
    #client[]はpythonの仕様じゃなくてpymongoの仕様、普通はclient.test_databaseでもいいけど'test-database'という
    #風に使いたい場合は['test-database']と書くディクショナリ型を使う
    db = client[urlparse(MONGO_URL).path[1:]] #.pathによって'/test'が抜き出されるそして[1:]によって前にある/が取り除かれる。
    #dbに突っ込むと勝手にDatabase()が付くのも仕様
    #print(db) Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'test')
    #存在するtestデータベースからIndexというコレクションを取り出す。
    col = db["Index"]
    #ここでコレクション"Index"を作っている。
    #print(col) Collection(Database(MongoClient(host=['localhost:27017'], document_class=dict, tz_aware=False, connect=True), 'test'), 'Index')
    
    
    
    def _split_to_word(text):
        """Japanese morphological analysis with janome.
        Splitting text and creating words list.
        """
        t = Tokenizer()
        #token.surfaceで日本語の文字だけ取り出せる。例えば車は高いだったら"車" "は" "高い" だけ取り出せる。
        return [token.surface for token in t.tokenize(text)]
    
    
    def _get_page(url):
        #r変数に<!DOCTYPE html>から代入する。
        r = requests.get(url)
        #レスポンスコードが200で正常だったら文字列""にして返す。
        if r.status_code == 200:
            return r.text
    
    
    def _extract_url_links(html):
        """extract url links
    
        >>> _extract_url_links('aa<a href="link1">link1</a>bb<a href="link2">link2</a>cc')
        ['link1', 'link2']
        """
        #"html.parser"はなるべくpython標準のparserモジュールを使うように指定しているBeautifulSoup()で
        #BeautifulSoupで扱えるようにしている。
        soup = BeautifulSoup(html, "html.parser")
        #aタグを全て持ってくる。
        return soup.find_all('a')
    
    
    def add_to_index(keyword, url):
        #DBからキーワードが含まれたドキュメントを持ってくるentryに代入する
        entry = col.find_one({'keyword': keyword})
        if entry:
            #entryの中にあるurlと引数のurlが同じじゃなければurlに引数のurlを追加して
            if url not in entry['url']:
                entry['url'].append(url)
                #DBに保存する。saveは追加よりも更新って感じ
                col.save(entry)
            return
        # not found, add new keyword to index
        col.insert({'keyword': keyword, 'url': [url]})
    
    
    def add_page_to_index(url, html):
        body_soup = BeautifulSoup(html, "html.parser").find('body')
        #htmlないの属性タグとその中身をchild_tagに入れていってる<body>以下にある全てのタグ<a>やら<th>やらを持ってくる。
        #先ずはbodyより下のhtml全部持ってきて次にその下のdivを持ってきてul持ってきてどんどん掘り下げる感じ
        for child_tag in body_soup.findChildren():
            #beautifulsoupの機能でタグの名前だけ取り出してる。スクリプトだけは避ける。それ以降の処理がスキップされてループに戻る
            if child_tag.name == 'script': #child_tag.nameタグの名前を取り出す
                continue
            #.textはそのタグの中身を表示する。<a>link</a>だったらlinkだけとりだす。
            child_text = child_tag.text
            for line in child_text.split('\n'): #文字列から改行を取り除いて分ける。
                line = line.rstrip().lstrip() #上のコードだけだと両端の空白が消せないからここで削除している。実際には削除はできないので取り除いたのを返している
                for word in _split_to_word(line): #janomaで日本語形態解析して単語をwordに代入
                    add_to_index(word, url)
    
    
    def crawl_web(seed, max_depth):
        to_crawl = {seed} #urlをto_crawlに入れて
        crawled = []
        next_depth = []
        depth = 0
        while to_crawl and depth <= max_depth:
            #回収したurlの後ろを削除しpage_urlに入れる。
            page_url = to_crawl.pop() #to_crawl（最初はurlが1つしか入らない）からurlを取り出して削除する
            if page_url not in crawled:
                html = _get_page(page_url)
                add_page_to_index(page_url, html)
                to_crawl = to_crawl.union(_extract_url_links(html)) #to_crawlに今まで入ってたurlとbf4で持ってきたurlを足してto_crawlに戻す最初0 + 5、4 + 2、5 + 0
                crawled.append(page_url)
            if not to_crawl:
                to_crawl, next_depth = next_depth, [] #next_depthいる？
                depth += 1
    
```
CC BY-SA 3.0
2017-10-24T17:12:18.603
39007
2017-10-25T15:40:36.130
2017-10-25T15:40:36.130
22565
22565
question
python python3 django mongodb flask
Pythonでimport仕組みがよくわからないです。エラーも出ますImportError: No module named 'config'
エラーが起きているのは、drop_collection.pyと同じディレクトリにconfig.pyファイルが存在しない為です。Pythonのコードに問題がある訳ではありません。

> ■検索エンジン  
>  |---■config.py  
>  |---■manage.py  
>  |---■web_crawler  
>  |---■__init__.py  
>  |---■crawler.py  
>  |---■drop_collection.py

上記のようなファイル階層になっている訳ですから、config.pyはdrop_collecction.pyのあるweb_crawlerディレクトリの親ディレクトリ("検索エンジン"ディレクトリ)に有るので、相対importを使ってください。
相対インポートというのは、.を使って相対的にインポート元を指定する方法です。

質問のコードの

```

    from config import MONGO_URL
    
```

を

```

    from ..config import MONGO_URL
    
```

に変更すると、一つ上の階層のconfig.pyをインポートするようになるので正常に動作すると思います。

teratailに同様の質問があって、それへのkatsukoさんの回答も参考にしてください。

[相対importという手段もあります。](https://teratail.com/questions/65319)

P.S.  
安直にconfig.pyファイルのコピーをweb_crawlerディレクトリに作るという方法もありますが、同名のファイルが複数あると後々メンテナンスが面倒になるのでお勧めしません。
CC BY-SA 3.0
2017-10-25T02:25:12.177
39011
2017-10-25T02:25:12.177
217
39007
answer