简介

requests底层是对urllib3进行的封装

快速上手

中文手册:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html

安装

pip install requests

发送请求

r = requests.get('https://github.com/timeline.json')
r = requests.post('http://httpbin.org/post')
r = requests.put('http://httpbin.org/put')
r = requests.delete('http://httpbin.org/delete')
r = requests.head('http://httpbin.org/get')
r = requests.options('http://httpbin.org/get')

传递URL参数

你也许经常想为URL的查询字符串(query string)传递某种数据。如果你是手工构建URL,那么数据会以键/值对的形式置于URL中,跟在一个问号的后面。例如,httpbin.org/get?key=val。Requests允许你使用params关键字参数,以一个字符串字典来提供这些参数。举例来说,如果你想传递key1=value1和key2=value2到httpbin.org/get,那么你可以使用如下代码:

>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.get("http://httpbin.org/get", params=payload)

通过打印输出该URL,你能看到URL已被正确编码:

>>> print(r.url)

http://httpbin.org/get?key2=value2&key1=value1

注意字典里值为None的键都不会被添加到URL的查询字符串里。

你还可以将一个列表作为值传入:

>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}

>>> r = requests.get('http://httpbin.org/get', params=payload)

>>> print(r.url)

http://httpbin.org/get?key1=value1&key2=value2&key2=value3

响应内容

我们能读取服务器响应的内容。再次以GitHub时间线为例:

>>> import requests

>>> r = requests.get('https://github.com/timeline.json')

>>> r.text

u'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests会自动解码来自服务器的内容。大多数unicode字符集都能被无缝地解码。

请求发出后,Requests会基于HTTP头部对响应的编码作出有根据的推测。当你访问r.text之时,Requests会使用其推测的文本编码。你可以找出Requests使用了什么编码,并且能够使用r.encoding属性来改变它:

>>> r.encoding

'utf-8'

>>> r.encoding = 'ISO-8859-1'

如果你改变了编码,每当你访问r.text,Request都将会使用r.encoding的新值。你可能希望在使用特殊逻辑计算出文本的编码的情况下来修改编码。比如HTTP和XML自身可以指定编码。这样的话,你应该使用r.content来找到编码,然后设置r.encoding为相应的编码。这样就能使用正确的编码解析r.text了。

在你需要的情况下,Requests也可以使用定制的编码。如果你创建了自己的编码,并使用codecs模块进行注册,你就可以轻松地使用这个解码器名称作为r.encoding的值,然后由Requests来为你处理编码。

二进制响应内容

你也能以字节的方式访问请求响应体,对于非文本请求:

>>> r.content

b'[{"repository":{"open_issues":0,"url":"https://github.com/...

Requests会自动为你解码gzip和deflate传输编码的响应数据。

例如,以请求返回的二进制数据创建一张图片,你可以使用如下代码:

>>> from PIL import Image

>>> from io import BytesIO

>>> i = Image.open(BytesIO(r.content))

JSON响应内容

Requests中也有一个内置的JSON解码器,助你处理JSON数据:

>>> import requests

>>> r = requests.get('https://github.com/timeline.json')

>>> r.json()

[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...

如果JSON解码失败,r.json()就会抛出一个异常。例如,响应内容是401 (Unauthorized),尝试访问r.json()将会抛出ValueError: No JSON object could be decoded异常。

需要注意的是,成功调用r.json()并**不**意味着响应的成功。有的服务器会在失败的响应中包含一个JSON对象(比如HTTP 500的错误细节)。这种JSON会被解码返回。要检查请求是否成功,请使用r.raise_for_status()或者检查r.status_code是否和你的期望相同。

原始响应内容

在罕见的情况下,你可能想获取来自服务器的原始套接字响应,那么你可以访问r.raw。如果你确实想这么干,那请你确保在初始请求中设置了stream=True。具体你可以这么做:

>>> r = requests.get('https://github.com/timeline.json', stream=True)

>>> r.raw

<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>

>>> r.raw.read(10)

'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'

但一般情况下,你应该以下面的模式将文本流保存到文件:

with open(filename, 'wb') as fd:

for chunk in r.iter_content(chunk_size):

fd.write(chunk)

使用Response.iter_content将会处理大量你直接使用Response.raw不得不处理的。当流下载时,上面是优先推荐的获取内容方式。Note thatchunk_sizecan be freely adjusted to a number that may better fit your use cases.

定制请求头

如果你想为请求添加HTTP头部,只要简单地传递一个dict给headers参数就可以了。

例如,在前一个示例中我们没有指定content-type:

>>> url = 'https://api.github.com/some/endpoint'

>>> headers = {'user-agent': 'my-app/0.0.1'}

>>> r = requests.get(url, headers=headers)

注意:定制header的优先级低于某些特定的信息源,例如:

  • 如果在.netrc中设置了用户认证信息,使用 headers= 设置的授权就不会生效。而如果设置了 auth=参数,``.netrc`` 的设置就无效了。

  • 如果被重定向到别的主机,授权header就会被删除。

  • 代理授权header会被URL中提供的代理身份覆盖掉。

  • 在我们能判断内容长度的情况下,header的Content-Length会被改写。

更进一步讲,Requests不会基于定制header的具体情况改变自己的行为。只不过在最后的请求中,所有的header信息都会被传递进去。

注意:所有的header值必须是string、bytestring或者unicode。尽管传递unicode header也是允许的,但不建议这样做。

更加复杂的POST请求

通常,你想要发送一些编码为表单形式的数据——非常像一个HTML表单。要实现这个,只需简单地传递一个字典给data参数。你的数据字典在发出请求时会自动编码为表单形式:

>>> payload = {'key1': 'value1', 'key2': 'value2'}

>>> r = requests.post("http://httpbin.org/post", data=payload)

>>> print(r.text)

{

...

"form": {

"key2": "value2",

"key1": "value1"

},

...

}

你还可以为data参数传入一个元组列表。在表单中多个元素使用同一key的时候,这种方式尤其有效:

>>> payload = (('key1', 'value1'), ('key1', 'value2'))

>>> r = requests.post('http://httpbin.org/post', data=payload)

>>> print(r.text)

{

...

"form": {

"key1": [

"value1",

"value2"

]

},

...

}

很多时候你想要发送的数据并非编码为表单形式的。如果你传递一个string而不是一个dict,那么数据会被直接发布出去。

例如,Github API v3接受编码为JSON的POST/PATCH数据:

>>> import json

>>> url = 'https://api.github.com/some/endpoint'

>>> payload = {'some': 'data'}

>>> r = requests.post(url, data=json.dumps(payload))

此处除了可以自行对dict进行编码,你还可以使用json参数直接传递,然后它就会被自动编码。这是2.4.2版的新加功能:

>>> url = 'https://api.github.com/some/endpoint'

>>> payload = {'some': 'data'}

>>> r = requests.post(url, json=payload)

POST一个多部分编码(Multipart-Encoded)的文件

Requests使得上传多部分编码文件变得很简单:

>>> url = 'http://httpbin.org/post'

>>> files = {'file': open('report.xls', 'rb')}

>>> r = requests.post(url, files=files)

>>> r.text

{

...

"files": {

"file": "<censored...binary...data>"

},

...

}

你可以显式地设置文件名,文件类型和请求头:

>>> url = 'http://httpbin.org/post'

>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}

>>> r = requests.post(url, files=files)

>>> r.text

{

...

"files": {

"file": "<censored...binary...data>"

},

...

}

如果你想,你也可以发送作为文件来接收的字符串:

>>> url = 'http://httpbin.org/post'

>>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}

>>> r = requests.post(url, files=files)

>>> r.text

{

...

"files": {

"file": "some,data,to,send\nanother,row,to,send\n"

},

...

}

如果你发送一个非常大的文件作为multipart/form-data请求,你可能希望将请求做成数据流。默认下requests不支持,但有个第三方包requests-toolbelt是支持的。你可以阅读toolbelt文档来了解使用方法。

在一个请求中发送多文件参考高级用法一节。

警告

我们强烈建议你用二进制模式(binary mode)打开文件。这是因为Requests可能会试图为你提供Content-Lengthheader,在它这样做的时候,这个值会被设为文件的字节数(bytes)。如果用文本模式(text mode)打开文件,就可能会发生错误。

响应码

我们可以检测响应状态码:

>>> r = requests.get("http://httpbin.org/get")

>>> r.status_code

200

为方便引用,Requests还附带了一个内置的状态码查询对象:

>>> r.status_code == requests.codes.ok

True

如果发送了一个错误请求(一个4XX客户端错误,或者5XX服务器错误响应),我们可以通过Response.raise_for_status()来抛出异常:

>>> bad_r = requests.get("http://httpbin.org/status/404")

>>> bad_r.status_code

404

>>> bad_r.raise_for_status()

Traceback (most recent call last):

File "requests/models.py", line 832, in raise_for_status

raise http_error

requests.exceptions.HTTPError: 404 Client Error

但是,由于我们的例子中r的status_code是200,当我们调用raise_for_status()时,得到的是:

>>> r.raise_for_status()

None

一切都挺和谐哈。

响应头

我们可以查看以一个Python字典形式展示的服务器响应头:

>>> r.headers

{

'content-encoding': 'gzip',

'transfer-encoding': 'chunked',

'connection': 'close',

'server': 'nginx/1.0.4',

'x-runtime': '148ms',

'etag': '"e1ca502697e5c9317743dc078f67693f"',

'content-type': 'application/json'

}

但是这个字典比较特殊:它是仅为HTTP头部而生的。根据RFC 2616,HTTP头部是大小写不敏感的。

因此,我们可以使用任意大写形式来访问这些响应头字段:

>>> r.headers['Content-Type']

'application/json'

>>> r.headers.get('content-type')

'application/json'

它还有一个特殊点,那就是服务器可以多次接受同一header,每次都使用不同的值。但Requests会将它们合并,这样它们就可以用一个映射来表示出来,参见RFC 7230:

A recipient MAY combine multiple header fields with the same field name into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field value to the combined field value in order, separated by a comma.

接收者可以合并多个相同名称的header栏位,把它们合为一个"field-name: field-value"配对,将每个后续的栏位值依次追加到合并的栏位值中,用逗号隔开即可,这样做不会改变信息的语义。

如果某个响应中包含一些cookie,你可以快速访问它们:

>>> url = 'http://example.com/some/cookie/setting/url'

>>> r = requests.get(url)

>>> r.cookies['example_cookie_name']

'example_cookie_value'

要想发送你的cookies到服务器,可以使用cookies参数:

>>> url = 'http://httpbin.org/cookies'

>>> cookies = dict(cookies_are='working')

>>> r = requests.get(url, cookies=cookies)

>>> r.text

'{"cookies": {"cookies_are": "working"}}'

Cookie的返回对象为RequestsCookieJar,它的行为和字典类似,但界面更为完整,适合跨域名跨路径使用。你还可以把Cookie Jar传到Requests中:

>>> jar = requests.cookies.RequestsCookieJar()

>>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')

>>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')

>>> url = 'http://httpbin.org/cookies'

>>> r = requests.get(url, cookies=jar)

>>> r.text

'{"cookies": {"tasty_cookie": "yum"}}'

补充:cookie_dict = response.cookies.get_dict()

重与请求历史

默认情况下,除了HEAD, Requests会自动处理所有重定向。

可以使用响应对象的history方法来追踪重定向。

Response.history是一个Response对象的列表,为了完成请求而创建了这些对象。这个对象列表按照从最老到最近的请求进行排序。

例如,Github将所有的HTTP请求重定向到HTTPS:

>>> r = requests.get("http://github.com")

>>> r.url

'https://github.com/'

>>> r.status_code

200

>>> r.history

[<Response [301]>]

如果你使用的是GET、OPTIONS、POST、PUT、PATCH或者DELETE,那么你可以通过allow_redirects参数禁用重定向处理:

>>> r = requests.get('http://github.com', allow_redirects=False)

>>> r.status_code

301

>>> r.history

[]

如果你使用了HEAD,你也可以启用重定向:

>>> r = requests.head('http://github.com', allow_redirects=True)

>>> r.url

'https://github.com/'

>>> r.history

[<Response [301]>]

超时

你可以告诉requests在经过以timeout参数设定的秒数时间之后停止等待响应。基本上所有的生产代码都应该使用这一参数。如果不使用,你的程序可能会永远失去响应:

>>> requests.get('http://github.com', timeout=0.001)

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)

注意

timeout仅对连接过程有效,与响应体的下载无关。timeout并不是整个下载响应的时间限制,而是如果服务器在timeout秒内没有应答,将会引发一个异常(更精确地说,是在timeout秒内没有从基础套接字上接收到任何字节的数据时)If no timeout is specified explicitly, requests do not time out.

错误与异常

遇到网络问题(如:DNS查询失败、拒绝连接等)时,Requests会抛出一个ConnectionError异常。

如果HTTP请求返回了不成功的状态码,Response.raise_for_status()会抛出一个HTTPError异常。

若请求超时,则抛出一个Timeout异常。

若请求超过了设定的最大重定向次数,则会抛出一个TooManyRedirects异常。

所有Requests显式抛出的异常都继承自requests.exceptions.RequestException

网页乱码的解决方案

# -*- coding:utf-8 -*-
# __author__ = u'张泽楠'
# __date__ = '2017/12/27 20:15'
"""
手动安装chardet工具包,自动检测内容的编码格式
"""
import requests, chardet
response = requests.get('http://search.51job.com/list/170200,000000,0000,00,9,99,python,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=')
print chardet.detect(r.content)
print response.encoding
response.encoding = chardet.detect(r.content)['encoding']
print response.text
import requests, chardet
response = requests.get('http://search.51job.com/list/170200,000000,0000,00,9,99,python,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=')
response.encoding = response.apparent_encoding
def param_method_url():
    # requests.request(method='get', url='http://127.0.0.1:8000/test/')
    # requests.request(method='post', url='http://127.0.0.1:8000/test/')
    pass


def param_param():
    # - 可以是字典
    # - 可以是字符串
    # - 可以是字节(ascii编码以内)

    # requests.request(method='get',
    # url='http://127.0.0.1:8000/test/',
    # params={'k1': 'v1', 'k2': '水电费'})

    # requests.request(method='get',
    # url='http://127.0.0.1:8000/test/',
    # params="k1=v1&k2=水电费&k3=v3&k3=vv3")

    # requests.request(method='get',
    # url='http://127.0.0.1:8000/test/',
    # params=bytes("k1=v1&k2=k2&k3=v3&k3=vv3", encoding='utf8'))

    # 错误
    # requests.request(method='get',
    # url='http://127.0.0.1:8000/test/',
    # params=bytes("k1=v1&k2=水电费&k3=v3&k3=vv3", encoding='utf8'))
    pass


def param_data():
    # 可以是字典
    # 可以是字符串
    # 可以是字节
    # 可以是文件对象

    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # data={'k1': 'v1', 'k2': '水电费'})

    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # data="k1=v1; k2=v2; k3=v3; k3=v4"
    # )

    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # data="k1=v1;k2=v2;k3=v3;k3=v4",
    # headers={'Content-Type': 'application/x-www-form-urlencoded'}
    # )

    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # data=open('data_file.py', mode='r', encoding='utf-8'), # 文件内容是:k1=v1;k2=v2;k3=v3;k3=v4
    # headers={'Content-Type': 'application/x-www-form-urlencoded'}
    # )
    pass


def param_json():
    # 将json中对应的数据进行序列化成一个字符串,json.dumps(...)
    # 然后发送到服务器端的body中,并且Content-Type是 {'Content-Type': 'application/json'}
    requests.request(method='POST',
                     url='http://127.0.0.1:8000/test/',
                     json={'k1': 'v1', 'k2': '水电费'})


def param_headers():
    # 发送请求头到服务器端
    requests.request(method='POST',
                     url='http://127.0.0.1:8000/test/',
                     json={'k1': 'v1', 'k2': '水电费'},
                     headers={'Content-Type': 'application/x-www-form-urlencoded'}
                     )


def param_cookies():
    # 发送Cookie到服务器端
    requests.request(method='POST',
                     url='http://127.0.0.1:8000/test/',
                     data={'k1': 'v1', 'k2': 'v2'},
                     cookies={'cook1': 'value1'},
                     )
    # 也可以使用CookieJar(字典形式就是在此基础上封装)
    from http.cookiejar import CookieJar
    from http.cookiejar import Cookie

    obj = CookieJar()
    obj.set_cookie(Cookie(version=0, name='c1', value='v1', port=None, domain='', path='/', secure=False, expires=None,
                          discard=True, comment=None, comment_url=None, rest={'HttpOnly': None}, rfc2109=False,
                          port_specified=False, domain_specified=False, domain_initial_dot=False, path_specified=False)
                   )
    requests.request(method='POST',
                     url='http://127.0.0.1:8000/test/',
                     data={'k1': 'v1', 'k2': 'v2'},
                     cookies=obj)


def param_files():
    # 发送文件
    # file_dict = {
    # 'f1': open('readme', 'rb')
    # }
    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # files=file_dict)

    # 发送文件,定制文件名
    # file_dict = {
    # 'f1': ('test.txt', open('readme', 'rb'))
    # }
    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # files=file_dict)

    # 发送文件,定制文件名
    # file_dict = {
    # 'f1': ('test.txt', "hahsfaksfa9kasdjflaksdjf")
    # }
    # requests.request(method='POST',
    # url='http://127.0.0.1:8000/test/',
    # files=file_dict)

    # 发送文件,定制文件名
    # file_dict = {
    #     'f1': ('test.txt', "hahsfaksfa9kasdjflaksdjf", 'application/text', {'k1': '0'})
    # }
    # requests.request(method='POST',
    #                  url='http://127.0.0.1:8000/test/',
    #                  files=file_dict)

    pass


def param_auth():
    from requests.auth import HTTPBasicAuth, HTTPDigestAuth

    ret = requests.get('https://api.github.com/user', auth=HTTPBasicAuth('wupeiqi', 'sdfasdfasdf'))
    print(ret.text)

    # ret = requests.get('http://192.168.1.1',
    # auth=HTTPBasicAuth('admin', 'admin'))
    # ret.encoding = 'gbk'
    # print(ret.text)

    # ret = requests.get('http://httpbin.org/digest-auth/auth/user/pass', auth=HTTPDigestAuth('user', 'pass'))
    # print(ret)
    #


def param_timeout():
    # ret = requests.get('http://google.com/', timeout=1)
    # print(ret)

    # ret = requests.get('http://google.com/', timeout=(5, 1))
    # print(ret)
    pass


def param_allow_redirects():
    ret = requests.get('http://127.0.0.1:8000/test/', allow_redirects=False)
    print(ret.text)


def param_proxies():
    # proxies = {
    # "http": "61.172.249.96:80",
    # "https": "http://61.185.219.126:3128",
    # }

    # proxies = {'http://10.20.1.128': 'http://10.10.1.10:5323'}

    # ret = requests.get("http://www.proxy360.cn/Proxy", proxies=proxies)
    # print(ret.headers)


    # from requests.auth import HTTPProxyAuth
    #
    # proxyDict = {
    # 'http': '77.75.105.165',
    # 'https': '77.75.105.165'
    # }
    # auth = HTTPProxyAuth('username', 'mypassword')
    #
    # r = requests.get("http://www.google.com", proxies=proxyDict, auth=auth)
    # print(r.text)

    pass


def param_stream():
    ret = requests.get('http://127.0.0.1:8000/test/', stream=True)
    print(ret.content)
    ret.close()

    # from contextlib import closing
    # with closing(requests.get('http://httpbin.org/get', stream=True)) as r:
    # # 在此处理响应。
    # for i in r.iter_content():
    # print(i)


def requests_session():
    import requests

    session = requests.Session()

    ### 1、首先登陆任何页面,获取cookie

    i1 = session.get(url="http://dig.chouti.com/help/service")

    ### 2、用户登陆,携带上一次的cookie,后台对cookie中的 gpsd 进行授权
    i2 = session.post(
        url="http://dig.chouti.com/login",
        data={
            'phone': "8615131255089",
            'password': "xxxxxx",
            'oneMonth': ""
        }
    )

    i3 = session.post(
        url="http://dig.chouti.com/link/vote?linksId=8589623",
    )
    print(i3.text)

参数示例

综合案例

自动登录抽屉网并点赞

# -*- coding:utf-8 -*-
# __author__ = u'张泽楠'
# __date__ = '2018/2/23 23:06'


import requests


r1 = requests.get(
    'http://dig.chouti.com/',
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0"
    }
)
r1_cookies = r1.cookies.get_dict()

print(r1_cookies)
post_dict = {
    "phone": '8618790868582',
    'password': 'zhangzenan',
    'oneMonth': 1
}
r2 = requests.post(
    url="http://dig.chouti.com/login",
    data=post_dict,
    cookies=r1_cookies,
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0"
    }
)

r3 = requests.post(
    url='http://dig.chouti.com/link/vote?linksId=17616671',
    cookies={'gpsd': r1_cookies.get('gpsd')},
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0"
    }
)
print(r3.text)




session = requests.Session()

### 1、首先登陆任何页面,获取cookie
i1 = session.get(
    url="http://dig.chouti.com/help/service",
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0"
    }
)

### 2、用户登陆,携带上一次的cookie,后台对cookie中的 gpsd 进行授权
i2 = session.post(
    url="http://dig.chouti.com/login",
    data={
        'phone': "8618790868582",
        'password': "zhangzenan",
        'oneMonth': ""
    },
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0"
    }
)

i3 = session.post(
    url="http://dig.chouti.com/link/vote?linksId=11837086",
    headers={
        "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:58.0) Gecko/20100101 Firefox/58.0"
    }

)
print(i3.text)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
import os
import datetime
import time
import json
# tree:树
# 通过etree可以将网页源码转换为一棵树
# 通过xpath对这棵树进行匹配
from lxml import etree

import sqlite3
from apscheduler.schedulers.blocking import BlockingScheduler
blocking = BlockingScheduler()


class ChouTi(object):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0",
    }

    @classmethod
    def unauthorized_car1(cls):
        print("准备获取未激活的卡1")
        url = "http://dig.chouti.com/"
        response = requests.get(url=url, headers=cls.headers)
        response.encoding = response.apparent_encoding
        cls.index_cookie = response.cookies.get_dict()
        print("获取未激活的卡1成功")

    @classmethod
    def authorized_car1(cls, phone, password):
        cls.connect = sqlite3.connect("chouti.db")
        cls.cursor = cls.connect.cursor()
        cls.cursor.execute("CREATE TABLE IF NOT EXISTS chouti(linksid text, status text DEFAULT '已点赞')")
        if os.path.exists("login.txt"):
            print("已经登录过!检测卡1有效性")
            one_month = datetime.timedelta(days=30)
            create_time = time.localtime(os.stat("login.txt").st_mtime)
            create_time = datetime.datetime(create_time.tm_year, create_time.tm_mon, create_time.tm_mday, create_time.tm_hour, create_time.tm_min, create_time.tm_sec)
            # 如果文件内保存的卡1信息没过期(在一个月内),直接取出来用
            if create_time + one_month > datetime.datetime.now():
                with open("login.txt", "r") as f:
                    # 通过json.loads把字符串重新转为字典
                    cls.index_cookie = json.loads(f.read())
                print("检测成功!卡1有效!")
                # 通过return强制返回,不让代码往下执行
                return
            else:
                print("检测成功!卡1失效!重新登录")
        else:
            print("没有登录!自动登录")
        # 如果文件不存在或者文件已经过期,重新登录
        cls.unauthorized_car1()
        print("准备激活卡1")
        url = "http://dig.chouti.com/login"
        data = {
            "phone": "86{}".format(phone),
            "password": str(password),
            "oneMonth": "1",
        }
        requests.post(url=url, headers=cls.headers, data=data, cookies=cls.index_cookie)
        print("激活卡1成功")
        with open("login.txt", "w") as f:
            # 字典不能直接存储,需要通过json.dumps转成字符串
            f.write(json.dumps(cls.index_cookie))

    @classmethod
    def dian_zan(cls, linksid):
        url = "http://dig.chouti.com/link/vote?linksId={}".format(linksid)
        response = requests.post(url=url, headers=cls.headers, cookies=cls.index_cookie)
        response.encoding = response.apparent_encoding
        print(response.text)

        cls.cursor.execute("INSERT INTO chouti (linksid) VALUES (?)", (linksid,))
        cls.connect.commit()

    @classmethod
    def cancle_dian_zan(cls, linksid):
        url = "http://dig.chouti.com/vote/cancel/vote.do"
        data = {
            "linksId": linksid
        }
        response = requests.post(url=url, headers=cls.headers, cookies=cls.index_cookie, data=data)
        response.encoding = response.apparent_encoding
        print(response.text)

        cls.cursor.execute("DELETE FROM chouti WHERE linksid=?", (linksid, ))
        cls.connect.commit()

    @classmethod
    def find_zan_id(cls, page=1):
        url = "http://dig.chouti.com/all/hot/recent/{}".format(page)
        response = requests.get(url=url, headers=cls.headers, cookies=cls.index_cookie)
        response.encoding = response.apparent_encoding
        content = response.content
        # 1. 可以通过正则表达式匹配
        # 2. 通过BS4匹配
        # 3. 通过xpath匹配 先导入工具包,

        # 1) 先把源码转换为树
        # root:根结点
        root = etree.HTML(content)
        # 2) 按照层级关系匹配数据
        lang_list = root.xpath("//div[@class='item']/div[@class='news-pic']/img/@lang")
        for linksid in lang_list:

            cls.cursor.execute("SELECT linksid  FROM chouti WHERE linksid=?", (linksid, ))
            result = cls.cursor.fetchone()
            if not result: # 如果没点赞
                cls.dian_zan(linksid)
            else: # 如果点过,跳过
                # cls.cancle_dian_zan(linksid)
                continue

        return True if "下一页" in response.text else False

    @classmethod
    def all_pages(cls):
        page = 0
        while True:
            page += 1
            print("-----------------------正在替第{}页点赞".format(page))
            next_page = cls.find_zan_id(page)
            print("-----------------------第{}页点赞完毕".format(page))
            if not next_page:
                break


@blocking.scheduled_job("interval", seconds=1000, id="run")
def run():
    ChouTi.authorized_car1("18790868582", "zhangzenan")
    ChouTi.all_pages()


if __name__ == '__main__':
    # run()
    blocking.start()

    # while True:
    #     ChouTi.authorized_car1("18790868582", "zhangzenan")
    #     ChouTi.all_pages()
    #     time.sleep(300)

各种接口

天气接口
http://api.map.baidu.com/telematics/v3/weather?location=郑州市&output=json&ak=TueGDhCvwI6fOrQnLM0qmXxY9N0OkOiQ&callback=?

电影接口(location=%s)
http://api.map.baidu.com/telematics/v3/movie?qt=hot_movie&location=郑州市&ak=TueGDhCvwI6fOrQnLM0qmXxY9N0OkOiQ&output=json

旅游接口(location=%s)
http://api.map.baidu.com/telematics/v3/travel_city?location=郑州&ak=TueGDhCvwI6fOrQnLM0qmXxY9N0OkOiQ&output=json

景点接口(输入景点拼音,id=%s)
http://api.map.baidu.com/telematics/v3/travel_attractions?id=yiheyuan&ak=TueGDhCvwI6fOrQnLM0qmXxY9N0OkOiQ&output=json

ip定位接口
http://api.map.baidu.com/location/ip?ak=KQvhEkxc6mFCAYHTblC3NGVmxzxIWk0E&coor=bd09ll


手机号接口
https://www.baifubao.com/callback?cmd=1059&callback=phone&phone=手机号

身份证接口
http://api.k780.com:88/?app=idcard.get&idcard=120103199901011990&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json 

歌曲查询接口
http://search.kuwo.cn/r.s?all=名称&ft=music&itemset=web_2013&client=kt&pn=第几页开始&rn=每页几条数据&rformat=json&encoding=utf8
注意:返回的数据都是单引号括起来的,不是json,需要把单引号换成双引号才行

results matching ""

    No results matching ""