├── README.md ├── gclid_timestamp_decoder ├── __init__.py ├── decode.py └── gclid_pb2.py └── setup.py /README.md: -------------------------------------------------------------------------------- 1 | # gclid timestamp decoder 2 | 3 | decoding timestamp from Google gclid using Protocol Buffers. 4 | 5 | ## overview 6 | 7 | message formats are defined in `.proto` files. each field in the message has a unique numbered tag (immutable once message type is in use). 8 | 9 | running the compiler on a `.proto` generates code in our chosen language (e.g. Python). with regards to Python: 10 | 11 | > a module is generated with a static descriptor of each message type, which is then used with a metaclass to create the necessary Python data accesss class at runtime. 12 | 13 | compiling the `.proto` using an example file we already pre-defined: 14 | 15 | protoc -I=$REPO_DIR --python_out=$DST_DIR $REPO_DIR/example.proto 16 | 17 | this generates example_pb2.py in the specified destination. 18 | 19 | ## additional presteps for base64 decode 20 | 21 | removing trailing bytes doesn't work, we will end up getting 22 | 23 | google.protobuf.message.DecodeError: Truncated message. 24 | 25 | instead, we resort to padding with `=` so we get the gclid to a multiple of 4 before decoding. 26 | 27 | ## requires 28 | 29 | - [Protocol Buffers 2.6](https://github.com/google/protobuf/releases/tag/v2.6.0) 30 | 31 | ## install 32 | 33 | pip install gclid-timestamp-decoder 34 | 35 | ## usage 36 | 37 | >>> from gclid_timestamp_decoder.decode import get_timestamp_from_gclid 38 | >>> get_timestamp_from_gclid("CKSDxc_qhLkCFQyk4AodO24Arg") 39 | '2013-08-17 23:50:17' 40 | 41 | 42 | ## references 43 | 44 | - [Protocol Buffers][2] 45 | 46 | - [Protocol Buffers Language Guide][3] 47 | 48 | - [Protocol Buffer Basics: Python][4] 49 | 50 | - [How to decode the gclid parameter in Google Adwords][1] 51 | 52 | ## author 53 | 54 | Contact [kenny@machinesung.com](mailto:kenny@machinesung.com) 55 | 56 | [1]: http://blog.deedpolloffice.com/articles/decoding-gclid-parameter 57 | [2]: https://developers.google.com/protocol-buffers/docs/overview 58 | [3]: https://developers.google.com/protocol-buffers/docs/proto 59 | [4]: https://developers.google.com/protocol-buffers/docs/pythontutorial 60 | -------------------------------------------------------------------------------- /gclid_timestamp_decoder/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qoelet/gclid-timestamp-decoder/9ec1864d042f52b76164e7833dd7a6b047239d12/gclid_timestamp_decoder/__init__.py -------------------------------------------------------------------------------- /gclid_timestamp_decoder/decode.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import datetime 3 | import gclid_pb2 4 | 5 | def decode(gclid): 6 | decoded_gclid = base64.urlsafe_b64decode(gclid + '=' * (4 - len(gclid) % 4)) 7 | g = gclid_pb2.Gclid() 8 | g.ParseFromString(decoded_gclid) 9 | return g 10 | 11 | def convert_to_dt(g): 12 | return datetime.datetime.fromtimestamp(g.timestamp / 1000000).strftime('%Y-%m-%d %H:%M:%S') 13 | 14 | def get_timestamp_from_gclid(gclid): 15 | return convert_to_dt(decode(gclid)) 16 | -------------------------------------------------------------------------------- /gclid_timestamp_decoder/gclid_pb2.py: -------------------------------------------------------------------------------- 1 | # Generated by the protocol buffer compiler. DO NOT EDIT! 2 | # source: gclid.proto 3 | 4 | from google.protobuf import descriptor as _descriptor 5 | from google.protobuf import message as _message 6 | from google.protobuf import reflection as _reflection 7 | from google.protobuf import descriptor_pb2 8 | # @@protoc_insertion_point(imports) 9 | 10 | 11 | 12 | 13 | DESCRIPTOR = _descriptor.FileDescriptor( 14 | name='gclid.proto', 15 | package='', 16 | serialized_pb='\n\x0bgclid.proto\"\x1a\n\x05Gclid\x12\x11\n\ttimestamp\x18\x01 \x02(\x03') 17 | 18 | 19 | 20 | 21 | _GCLID = _descriptor.Descriptor( 22 | name='Gclid', 23 | full_name='Gclid', 24 | filename=None, 25 | file=DESCRIPTOR, 26 | containing_type=None, 27 | fields=[ 28 | _descriptor.FieldDescriptor( 29 | name='timestamp', full_name='Gclid.timestamp', index=0, 30 | number=1, type=3, cpp_type=2, label=2, 31 | has_default_value=False, default_value=0, 32 | message_type=None, enum_type=None, containing_type=None, 33 | is_extension=False, extension_scope=None, 34 | options=None), 35 | ], 36 | extensions=[ 37 | ], 38 | nested_types=[], 39 | enum_types=[ 40 | ], 41 | options=None, 42 | is_extendable=False, 43 | extension_ranges=[], 44 | serialized_start=15, 45 | serialized_end=41, 46 | ) 47 | 48 | DESCRIPTOR.message_types_by_name['Gclid'] = _GCLID 49 | 50 | class Gclid(_message.Message): 51 | __metaclass__ = _reflection.GeneratedProtocolMessageType 52 | DESCRIPTOR = _GCLID 53 | 54 | # @@protoc_insertion_point(class_scope:Gclid) 55 | 56 | 57 | # @@protoc_insertion_point(module_scope) 58 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup(name='gclid-timestamp-decoder', 4 | version='0.1.2', 5 | description='Decoding timestamp from Google gclid using Protocol Buffers.', 6 | author='Kenny Shen', 7 | author_email='kenny@machinesung.com', 8 | license='BSD', 9 | url='https://github.com/qoelet/gclid-timestamp-decoder', 10 | download_url='https://pypi.python.org/pypi/gclid-timestamp-decoder', 11 | install_requires=['protobuf==2.6'], 12 | packages=['gclid_timestamp_decoder'] 13 | ) 14 | --------------------------------------------------------------------------------