├── .coveragerc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.rst ├── bin └── isort.sh ├── opengraph ├── __init__.py └── opengraph.py ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── run_tests.py └── test_opengraph.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source=opengraph 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | 59 | # SublimeText project/workspace 60 | *.sublime* 61 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 2.7 5 | - 3.3 6 | - 3.4 7 | - pypy 8 | 9 | install: 10 | - pip install . 11 | - pip install flake8 isort pep8-naming coverage coveralls 12 | 13 | before_script: 14 | - chmod -R +x ./bin 15 | - ./bin/isort.sh 16 | - flake8 --max-complexity 10 opengraph 17 | 18 | script: 19 | - python setup.py test 20 | - coverage run setup.py test 21 | 22 | after_success: 23 | - coveralls 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Henrik Ossipoff Hansen 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 | 23 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://travis-ci.org/HenrikOssipoff/python-opengraph.svg?branch=master 2 | :target: https://travis-ci.org/HenrikOssipoff/python-opengraph 3 | .. image:: https://coveralls.io/repos/HenrikOssipoff/python-opengraph/badge.svg?branch=master 4 | :target: https://coveralls.io/r/HenrikOssipoff/python-opengraph?branch=master 5 | 6 | ❗ This repository is no longer maintained in any way. PRs will not be responded to ❗ 7 | 8 | Python module to parse Open Graph metadata on web pages. For more information on the Open Graph Protocol, see http://ogp.me/. 9 | 10 | Compatability 11 | ============= 12 | - Python 2.7 13 | - Python 3.3, 3.4 14 | - PyPy 15 | 16 | Other versions may work, but testing is only done against the above versions. 17 | 18 | Dependencies 19 | ============ 20 | - Beautiful Soup 4 21 | - Requests 22 | 23 | Installation 24 | ============ 25 | .. code:: python 26 | 27 | pip install python-opengraph 28 | 29 | Example loading from URL 30 | ======================== 31 | .. code:: python 32 | 33 | from opengraph import OpenGraph 34 | 35 | og = OpenGraph(url='http://someurl.com') 36 | og.title # would yield the 'title' open graph element 37 | -------------------------------------------------------------------------------- /bin/isort.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | o=$(isort -rc -cs --diff opengraph) 4 | echo "${o}" 5 | size=${#o} 6 | if [ "${size}" != 0 ]; then 7 | exit 1 8 | fi 9 | -------------------------------------------------------------------------------- /opengraph/__init__.py: -------------------------------------------------------------------------------- 1 | from .opengraph import OpenGraph # NOQA 2 | -------------------------------------------------------------------------------- /opengraph/opengraph.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | import re 5 | 6 | import requests 7 | from bs4 import BeautifulSoup 8 | 9 | 10 | class OpenGraph(object): 11 | useragent = None 12 | __data__ = {} 13 | 14 | def __init__(self, url=None, html=None, useragent=None): 15 | if useragent: 16 | self.useragent = useragent 17 | content = html or self._fetch(url) 18 | self._parse(content) 19 | 20 | def __contains__(self, item): 21 | return item in self.__data__ 22 | 23 | def __getattr__(self, name): 24 | if name in self.__data__: 25 | return self.__data__[name] 26 | raise AttributeError( 27 | 'Open Graph object has no attribute "{}"'.format(name)) 28 | 29 | def __repr__(self): 30 | return self.__data__.__str__() 31 | 32 | def __str__(self): 33 | return self.__repr__() 34 | 35 | def _fetch(self, url): 36 | headers = {} 37 | if self.useragent: 38 | headers = { 39 | 'user-agent': self.useragent 40 | } 41 | response = requests.get(url, headers=headers) 42 | return response.text 43 | 44 | def _parse(self, html): 45 | doc = BeautifulSoup(html) 46 | ogs = doc.html.head.findAll(property=re.compile(r'^og')) 47 | 48 | for og in ogs: 49 | if og.has_attr('content'): 50 | self.__data__[og['property'][3:]] = og['content'] 51 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal = 1 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from setuptools import setup, find_packages 5 | 6 | VERSION = (0, 0, 3) 7 | __version__ = VERSION 8 | __versionstr__ = '.'.join([str(v) for v in VERSION]) 9 | 10 | install_requires = ['beautifulsoup4>=4.3', 'requests>=2.7'] 11 | test_require = install_requires + ['coverage>=3.7', 'nose>=1.3', 'responses'] 12 | 13 | setup( 14 | name='python-opengraph', 15 | version=__versionstr__, 16 | description='Python module to parse Open Graph metadata on web pages', 17 | url='https://github.com/HenrikOssipoff/python-opengraph', 18 | license='MIT', 19 | author='Henrik Ossipoff Hansen', 20 | author_email='henrik.ossipoff@gmail.com', 21 | install_requires=install_requires, 22 | packages=find_packages(exclude=['tests']), 23 | tests_require=test_require, 24 | test_suite='tests.run_tests.all', 25 | classifiers=[ 26 | 'Development Status :: 3 - Alpha', 27 | 'Intended Audience :: Developers', 28 | 'License :: OSI Approved :: MIT License', 29 | 'Operating System :: OS Independent', 30 | 'Programming Language :: Python :: 2', 31 | 'Programming Language :: Python :: 2.7', 32 | 'Programming Language :: Python :: 3', 33 | 'Programming Language :: Python :: 3.3', 34 | 'Programming Language :: Python :: 3.4', 35 | 'Programming Language :: Python :: Implementation :: PyPy' 36 | ], 37 | keywords='opengraph') 38 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HenrikOssipoff/python-opengraph/1ca2470f45e901001b7a76e959a6a3d52ba9646b/tests/__init__.py -------------------------------------------------------------------------------- /tests/run_tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from os.path import abspath, dirname 5 | 6 | import nose 7 | 8 | 9 | def all(): 10 | argv = ['nosetests', '--verbose', '--logging-level=ERROR'] 11 | nose.run_exit(argv=argv, defaultTest=abspath(dirname(__file__))) 12 | 13 | if __name__ == '__main__': 14 | all() 15 | -------------------------------------------------------------------------------- /tests/test_opengraph.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import absolute_import, unicode_literals 3 | 4 | from unittest import TestCase 5 | 6 | from opengraph import OpenGraph 7 | from threading import local 8 | import responses 9 | 10 | data = local() 11 | 12 | 13 | class TestOpenGraph(TestCase): 14 | def setUp(self): # NOQA 15 | self.test_document = """ 16 | 17 | 18 | 19 | """ 20 | 21 | @responses.activate 22 | def test_loading_from_url(self): 23 | url = 'http://foo.bar.com/' 24 | responses.add( 25 | responses.GET, url, body=self.test_document, 26 | status=200, content_type='text/html') 27 | og = OpenGraph(url=url) 28 | self.assertEqual(og.title, 'Test title') 29 | 30 | def test_get_attr(self): 31 | og = OpenGraph(html=self.test_document) 32 | self.assertEqual(og.title, 'Test title') 33 | with self.assertRaises(AttributeError): 34 | og.attribute_does_not_exist 35 | 36 | def test_contains(self): 37 | og = OpenGraph(html=self.test_document) 38 | self.assertIn('title', og) 39 | 40 | def test_str_repr(self): 41 | og = OpenGraph(html=self.test_document) 42 | text_of_data = og.__data__.__str__() 43 | self.assertEqual(str(og), text_of_data) 44 | 45 | @responses.activate 46 | def test_loading_from_url(self): 47 | def http_callback(request): 48 | # Ugly, but using thread locals in order to capture the request 49 | # headers in the callback, to assert that it's being set correctly 50 | data.headers = request.headers 51 | return (200, {'content-type': 'text/html'}, self.test_document) 52 | 53 | url = 'http://foo.bar.com/' 54 | useragent = 'python-opengraph/0.0' 55 | responses.add_callback( 56 | responses.GET, url, callback=http_callback, 57 | content_type='text/html') 58 | og = OpenGraph(url=url, useragent=useragent) 59 | headers = data.headers 60 | self.assertEqual(og.title, 'Test title') 61 | self.assertEqual(headers['user-agent'], useragent) 62 | --------------------------------------------------------------------------------