├── .github └── dependabot.yml ├── .gitignore ├── LICENSE ├── README.md ├── requirements.txt └── wick.py /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Decagon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wick 2 | Browse the internet like your filesystem. 3 | 4 | [![Updates](https://pyup.io/repos/github/Decagon/wick/shield.svg)](https://pyup.io/repos/github/Decagon/wick/) [![Python 3](https://pyup.io/repos/github/Decagon/wick/python-3-shield.svg)](https://pyup.io/repos/github/Decagon/wick/) 5 | 6 | ## Usage 7 | 8 | ```python 9 | wickInstance = Wick() 10 | wickInstance.set("google.ca") 11 | wickInstance.cd("images") 12 | ``` 13 | `>>> 'http://google.ca/images'` 14 | 15 | ```python 16 | wickInstance.rm("object.html") 17 | ``` 18 | `>>> DEL 'http://google.ca/images/objects.html' (sends http DEL request)` 19 | 20 | ```python 21 | wickInstance.cd("..") 22 | print wickInstance.pwd() 23 | ``` 24 | `>>> 'http://google.ca/'` 25 | 26 | ```python 27 | wickInstance.ls() 28 | ``` 29 | 30 | ```bash 31 | http://google.ca 32 | http://www.google.ca/imghp?hl=en&tab=wi 33 | http://maps.google.ca/maps?hl=en&tab=wl 34 | https://play.google.com/?hl=en&tab=w8 35 | http://www.youtube.com/?gl=CA&tab=w1 36 | http://news.google.ca/nwshp?hl=en&tab=wn 37 | https://mail.google.com/mail/?tab=wm 38 | https://drive.google.com/?tab=wo 39 | https://www.google.ca/intl/en/options/ 40 | http://www.google.ca/history/optout?hl=en 41 | /preferences?hl=en 42 | https://accounts.google.com/ServiceLogin?hl=en&passive=true&continue=http://www.google.ca/ 43 | /advanced_search?hl=en-CA&authuser=0 44 | /language_tools?hl=en-CA&authuser=0 45 | http://www.google.ca/setprefs?sig=&hl=fr&source=homepage 46 | /intl/en/ads/ 47 | /services/ 48 | /intl/en/about.html 49 | http://www.google.ca/setprefdomain?prefdom=US&sig= 50 | /intl/en/policies/privacy/ 51 | /intl/en/policies/terms/ 52 | ``` 53 | 54 | ```python 55 | wickInstance.cp("http://example.com/file.zip", ".")* 56 | ``` 57 | 58 | ```bash 59 | >>> GET 'http://example.com/file.zip' -> PUT (upload) 'http://google.ca/file.zip' 60 | ``` 61 | 62 | This example will download `file.zip` from example.com, then upload it to google.ca with a PUT request with the same file name and content type. 63 | 64 | ```python 65 | wickInstance.mv("http://example.com/file.zip", "http://google.ca/")* 66 | ``` 67 | 68 | ```bash 69 | >>> GET 'http://example.com/file.zip' -> PUT (upload) 'http://google.ca/file.zip' -> DEL 'http://example.com/file.zip' 70 | ``` 71 | 72 | This will download `'file.zip` from example.com, upload it to google.ca, then send a DEL request to example.com 73 | 74 | Copying and moving files is on the roadmap. 75 | 76 | ## Roadmap 77 | 78 | Implement these linux utilities: `find` (would have to recrusively search web dir; would be slow), `cmp`, and support piping output of websites to other linux utilities. 79 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.12.4 2 | lxml==4.1.1 3 | -------------------------------------------------------------------------------- /wick.py: -------------------------------------------------------------------------------- 1 | import urllib.parse 2 | import requests 3 | from requests.auth import HTTPBasicAuth 4 | 5 | 6 | class Wick: 7 | def __init__(self, url=None): 8 | self.url = url 9 | self.response = None 10 | self.username = None 11 | self.password = None 12 | 13 | # http authentication 14 | def login(self, username, password): 15 | self.username = username 16 | self.password = password 17 | 18 | # set the url 19 | def set(self, url): 20 | if not url.startswith("http://") and \ 21 | not url.startswith("https://"): 22 | url = "http://" + url 23 | self.url = url 24 | 25 | # download the webpage 26 | def get(self): 27 | response = None 28 | self.response = requests.get(self.url) 29 | 30 | # returns the downloaded webpage 31 | def payload(self): 32 | return self.response 33 | 34 | def pwd(self): 35 | return self.url 36 | 37 | # gets all links on webpage (including out of domain links) 38 | def ls(self): 39 | import urllib 40 | import lxml.html 41 | connection = urllib.urlopen(self.url) 42 | 43 | dom = lxml.html.fromstring(connection.read()) 44 | 45 | # select the url in href for all a tags(links) 46 | for link in dom.xpath('//a/@href'): 47 | print(link) 48 | 49 | def rm(self, theData): 50 | theUrl = self.url 51 | return requests.delete(theUrl, 52 | auth=HTTPBasicAuth( 53 | self.username, 54 | self.password)) 55 | 56 | # copies a local or remote file to the server 57 | def cp(self, theData): 58 | if (theData.startswith('http://') or 59 | theData.startswith('https://')) and \ 60 | "\n" not in theData: 61 | theData = requests.get(theData) 62 | 63 | return requests.put(self.url, data=theData) 64 | 65 | def cd(self, cdLocation): 66 | url = None 67 | cdLocation = cdLocation.strip() 68 | if cdLocation == "..": 69 | url = '/'.join(self.url.split("/")[:-1]) 70 | else: 71 | if "." in cdLocation: 72 | url = urlparse.urljoin(self.url + "/", cdLocation) 73 | else: 74 | url = urlparse.urljoin(self.url, cdLocation) 75 | 76 | self.url = url 77 | return url 78 | --------------------------------------------------------------------------------