爬蟲之Requests&beautifulsoup

  網絡爬蟲(又被稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更常常的稱爲網頁追逐者),是一種按照必定的規則,自動地抓取萬維網信息的程序或者腳本。另一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。

目錄

1、Requests

2、BeautifulSoup

3、自動登錄抽屜並點贊

4、「破解」微信公衆號

5、自動登錄示例

1、Requests

Python標準庫中提供了:urllib、urllib二、httplib等模塊以供Http請求,可是,它的 API 太渣了。它是爲另外一個時代、另外一個互聯網所建立的。它須要巨量的工做,甚至包括各類方法覆蓋,來完成最簡單的任務。html

  • 封裝urllib請求
import urllib2
import json
import cookielib


def urllib2_request(url, method="GET", cookie="", headers={}, data=None):
    """
    :param url: 要請求的url
    :param cookie: 請求方式,GET、POST、DELETE、PUT..
    :param cookie: 要傳入的cookie,cookie= 'k1=v1;k1=v2'
    :param headers: 發送數據時攜帶的請求頭,headers = {'ContentType':'application/json; charset=UTF-8'}
    :param data: 要發送的數據GET方式須要傳入參數,data={'d1': 'v1'}
    :return: 返回元祖,響應的字符串內容 和 cookiejar對象
    對於cookiejar對象,可使用for循環訪問:
        for item in cookiejar:
            print item.name,item.value
    """
    if data:
        data = json.dumps(data)

    cookie_jar = cookielib.CookieJar()
    handler = urllib2.HTTPCookieProcessor(cookie_jar)
    opener = urllib2.build_opener(handler)
    opener.addheaders.append(['Cookie', 'k1=v1;k1=v2'])
    request = urllib2.Request(url=url, data=data, headers=headers)
    request.get_method = lambda: method

    response = opener.open(request)
    origin = response.read()

    return origin, cookie_jar


# GET
result = urllib2_request('http://127.0.0.1:8001/index/', method="GET")

# POST
result = urllib2_request('http://127.0.0.1:8001/index/',  method="POST", data= {'k1': 'v1'})

# PUT
result = urllib2_request('http://127.0.0.1:8001/index/',  method="PUT", data= {'k1': 'v1'})

Requests 是使用 Apache2 Licensed 許可證的 基於Python開發的HTTP 庫,其在Python內置模塊的基礎上進行了高度的封裝,從而使得Pythoner進行網絡請求時,變得美好了許多,使用Requests能夠垂手可得的完成瀏覽器可有的任何操做。python

一、GET請求git

# 一、無參數實例
 
import requests
 
ret = requests.get('https://github.com/timeline.json')
 
print ret.url
print ret.text
 
# 二、有參數實例
 
import requests
 
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get("http://httpbin.org/get", params=payload)
 
print ret.url
print ret.text

向 https://github.com/timeline.json 發送一個GET請求,將請求和響應相關均封裝在 ret 對象中。github

實例:爬取汽車之家新聞標題、連接和圖片ajax

import requests
import scrapy
from bs4 import BeautifulSoup
import os
import uuid

response = requests.get(url='https://www.autohome.com.cn/news/',)
# 用下載自帶的編碼規則解析
# 也能夠指定response.encoding = 'utf-8'
response.encoding = response.apparent_encoding
# response.status_code 返回的狀態碼
# lxml性能更好,但須要安裝,html.parser是Python內置的
soup = BeautifulSoup(response.text,features='html.parser')
tag1 = soup.find(id='auto-channel-lazyload-article')
# tag2 = tag1.find('li') # 只找到第一個
tag_list = tag1.find_all('li')  # 找到所有,以列表形式輸出
for tag in tag_list:
    tag_a = tag.find('a')
    if tag_a:  # 有a標籤的纔拿屬性
        # print(tag_a.attrs.get('href')) # 新聞連接
        h3_text = tag_a.find('h3')  # 實際上是一個對象,只是打印的時候顯示文本
        # text和string都是獲取標籤對象的文本
        # print(h3_text.string,'*****') # 新聞標題
        # print(h3_text.text,'----')   # 新聞標題
        img_url = tag_a.find('img').attrs.get('src')
        # print(img_url) # 新聞圖片
        # 下載圖片,.text返回的是文本,.content返回的是字節
        # 若是直接寫url=img_url,最後會出現http:////p9.pstatp.com/list/pgc-image/153838020
        img_response = requests.get("http:" + img_url).content
        file_name = 'imgs/' + str(uuid.uuid4()) + '.jpg'
        # with open(file_name,'wb') as f:
        #     f.write(img_response)

二、POST請求正則表達式

# 一、基本POST實例
 
import requests
 
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
 
print ret.text
 
# 二、發送請求頭和數據實例
 
import requests
import json
 
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
 
ret = requests.post(url, data=json.dumps(payload), headers=headers)
 
print ret.text
print ret.cookies

向https://api.github.com/some/endpoint發送一個POST請求,將請求和相應相關的內容封裝在 ret 對象中。json

三、其餘請求api

requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
 
# 以上方法均是在此方法的基礎上構建
requests.request(method, url, **kwargs)
params={'k1':'v1'} 以GET形式放入URL傳到後臺的參數

requests模塊已經將經常使用的Http請求方法爲用戶封裝完成,用戶直接調用其提供的相應方法便可,其中方法的全部參數有:瀏覽器

def request(method, url, **kwargs):
    """Constructs and sends a :class:`Request <Request>`.

    :param method: method for the new :class:`Request` object.
    :param url: URL for the new :class:`Request` object.
    :param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
    :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
    :param json: (optional) json data to send in the body of the :class:`Request`.
    :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
    :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
    :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': ('filename', fileobj)}``) for multipart encoding upload.
    :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
    :param timeout: (optional) How long to wait for the server to send data
        before giving up, as a float, or a :ref:`(connect timeout, read
        timeout) <timeouts>` tuple.
    :type timeout: float or tuple
    :param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
    :type allow_redirects: bool
    :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
    :param verify: (optional) whether the SSL cert will be verified. A CA_BUNDLE path can also be provided. Defaults to ``True``.
    :param stream: (optional) if ``False``, the response content will be immediately downloaded.
    :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
    :return: :class:`Response <Response>` object
    :rtype: requests.Response

    Usage::

      >>> import requests
      >>> req = requests.request('GET', 'http://httpbin.org/get')
      <Response [200]>
    """

    # By using the 'with' statement we are sure the session is closed, thus we
    # avoid leaving sockets open which can trigger a ResourceWarning in some
    # cases, and look like a memory leak in others.
    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)
View Code

參數示例:服務器

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/')
    


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'))
    


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'}
    )
    


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)


def param_auth():
# 基本認證(原理:在headers中加入加密的用戶名和密碼)
    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)



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()

    ### 一、首先登錄任何頁面,獲取cookie

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

    ### 二、用戶登錄,攜帶上一次的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)

# 補充
# param verify: 是否忽略證書,直接進行訪問;verify=False, # 忽略證書
# param cert:證書文件;# cert='xx.pem',  # pem類型證書,cert = ('xx.crt','oo.key'),# 組合證書,功能同樣

# Referer: https://www.baidu.com/ 請求頭裏記錄上一次的訪問地址
# User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
# 請求頭裏表示你當前訪問用的客戶端類型
View Code

更多requests模塊相關的文檔見:http://cn.python-requests.org/zh_CN/latest/

2、BeautifulSoup

BeautifulSoup是一個模塊,該模塊用於接收一個HTML或XML字符串,而後將其進行格式化,以後遍可使用他提供的方法進行快速查找指定元素,從而使得在HTML或XML中查找指定元素變得簡單。

  • 安裝:pip install beautifulsoup4
  • 調用:from bs4 import BeautifulSoup

簡單實例:

from bs4 import BeautifulSoup
 
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
asdf
    <div class="title">
        <b>The Dormouse's story總共</b>
        <h1>f</h1>
    </div>
<div class="story">Once upon a time there were three little sisters; and their names were
    <a  class="sister0" id="link1">Els<span>f</span>ie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</div>
ad<br/>sf
<p class="story">...</p>
</body>
</html>
"""
 
soup = BeautifulSoup(html_doc, features="lxml")
# 找到第一個a標籤
tag1 = soup.find(name='a')
# 找到全部的a標籤
tag2 = soup.find_all(name='a')
# 找到id=link2的標籤
tag3 = soup.select('#link2')

1. name,標籤名稱

# tag = soup.find('a')
# name = tag.name # 獲取
# print(name)
# tag.name = 'span' # 設置
# print(soup)

2. attr,標籤屬性

# tag = soup.find('a')
# attrs = tag.attrs    # 獲取
# print(attrs)
# tag.attrs = {'ik':123} # 設置
# tag.attrs['id'] = 'iiiii' # 設置
# print(soup)

3. children,全部子標籤

# body = soup.find('body')
# v = body.children

4.descendants,全部子子孫孫標籤,獲得一個迭代器,可list()轉換成列表,它內部幫咱們作迭代;它會先找到標籤,再找到標籤內部的全部內容,包括文本,一條線走到底;

body = soup.find('body').descendants

5. clear,將標籤的全部子標籤所有清空(保留標籤名)

# tag = soup.find('body')
# tag.clear()
# print(soup)

6. decompose,遞歸的刪除全部的標籤

# body = soup.find('body')
# body.decompose()
# print(soup)

7. extract,遞歸的刪除全部的標籤,並獲取刪除的標籤

# body = soup.find('body')
# v = body.extract()
# print(soup)

8. decode,轉換爲字符串(含當前標籤);decode_contents(不含當前標籤)

# body = soup.find('body')
# v = body.decode()
# v = body.decode_contents()
# print(v)

9. encode,轉換爲字節(含當前標籤);encode_contents(不含當前標籤)

# body = soup.find('body')
# v = body.encode()
# v = body.encode_contents()
# print(v)

10. find,獲取匹配的第一個標籤

# tag = soup.find('a')
# print(tag)
# 組合使用
tag = soup.find(id='c1')
tag = soup.find('div',id='c1')
# tag = soup.find(name='a', attrs={'class': 'sister'}, recursive=True, text='Lacie')
# tag = soup.find(name='a', class_='sister', recursive=True, text='Lacie')
# print(tag)

11. find_all,獲取匹配的全部標籤,以列表形式輸出

# tags = soup.find_all('a')
# print(tags)
 
# tags = soup.find_all('a',limit=1)
# print(tags)
 
# tags = soup.find_all(name='a', attrs={'class': 'sister'}, recursive=True, text='Lacie')
# # tags = soup.find(name='a', class_='sister', recursive=True, text='Lacie')
# print(tags)
 
 
# ####### 列表 #######
# v = soup.find_all(name=['a','div'])
# print(v)
 
# v = soup.find_all(class_=['sister0', 'sister'])
# print(v)
 
# v = soup.find_all(text=['Tillie'])
# print(v, type(v[0]))
 
 
# v = soup.find_all(id=['link1','link2'])
# print(v)
 
# v = soup.find_all(href=['link1','link2'])
# print(v)
 
# ####### 正則 #######
import re
# rep = re.compile('p')
# rep = re.compile('^p')
# v = soup.find_all(name=rep)
# print(v)
 
# rep = re.compile('sister.*')
# v = soup.find_all(class_=rep)
# print(v)
 
# rep = re.compile('http://www.oldboy.com/static/.*')
# v = soup.find_all(href=rep)
# print(v)
 
# ####### 方法篩選 #######
# def func(tag):
# return tag.has_attr('class') and tag.has_attr('id')
# v = soup.find_all(name=func)
# print(v)
 
 
# ## get,獲取標籤屬性
# tag = soup.find('a')
# v = tag.get('id')
# print(v)

12. has_attr,檢查標籤是否具備該屬性

# tag = soup.find('a')
# v = tag.has_attr('id')
# print(v)

13. get_text,獲取標籤內部文本內容

# tag = soup.find('a')
# v = tag.get_text()
# print(v)

14. index,檢查標籤在某標籤中的索引位置

# tag = soup.find('body')
# v = tag.index(tag.find('div'))
# print(v)
 
# tag = soup.find('body')
# for i,v in enumerate(tag):
# print(i,v)

15. is_empty_element,是不是空標籤(是否能夠是空)或者自閉合標籤,

     判斷是不是以下標籤:'br' , 'hr', 'input', 'img', 'meta','spacer', 'link', 'frame', 'base'

# tag = soup.find('br')
# v = tag.is_empty_element
# print(v)

16. 當前的關聯標籤

# soup.next
# soup.next_element
# soup.next_elements
# soup.next_sibling
# soup.next_siblings
 
#
# tag.previous
# tag.previous_element
# tag.previous_elements
# tag.previous_sibling
# tag.previous_siblings
 
#
# tag.parent
# tag.parents

17. 查找某標籤的關聯標籤

# tag.find_next(...)
# tag.find_all_next(...)
# tag.find_next_sibling(...)
# tag.find_next_siblings(...)
 
# tag.find_previous(...)
# tag.find_all_previous(...)
# tag.find_previous_sibling(...)
# tag.find_previous_siblings(...)
 
# tag.find_parent(...)
# tag.find_parents(...)
 
# 參數同find_all

18. select,select_one, CSS選擇器

soup.select("title")
 
soup.select("p nth-of-type(3)")
 
soup.select("body a")
 
soup.select("html head title")
 
tag = soup.select("span,a")
 
soup.select("head > title")
 
soup.select("p > a")
 
soup.select("p > a:nth-of-type(2)")
 
soup.select("p > #link1")
 
soup.select("body > a")
 
soup.select("#link1 ~ .sister")
 
soup.select("#link1 + .sister")
 
soup.select(".sister")
 
soup.select("[class~=sister]")
 
soup.select("#link1")
 
soup.select("a#link2")
 
soup.select('a[href]')
 
soup.select('a[href="http://example.com/elsie"]')
 
soup.select('a[href^="http://example.com/"]')
 
soup.select('a[href$="tillie"]')
 
soup.select('a[href*=".com/el"]')
 
 
from bs4.element import Tag
 
def default_candidate_generator(tag):
    for child in tag.descendants:
        if not isinstance(child, Tag):
            continue
        if not child.has_attr('href'):
            continue
        yield child
 
tags = soup.find('body').select("a", _candidate_generator=default_candidate_generator)
print(type(tags), tags)
 
from bs4.element import Tag
def default_candidate_generator(tag):
    for child in tag.descendants:
        if not isinstance(child, Tag):
            continue
        if not child.has_attr('href'):
            continue
        yield child
 
tags = soup.find('body').select("a", _candidate_generator=default_candidate_generator, limit=1)
print(type(tags), tags)

19. 標籤的內容,response.text和response.string結果同樣

# tag = soup.find('span')
# print(tag.string)          # 獲取
# tag.string = 'new content' # 設置
# print(soup)
 
# tag = soup.find('body')
# print(tag.string)
# tag.string = 'xxx'
# print(soup)
 
# tag = soup.find('body')
# v = tag.stripped_strings  # 遞歸內部獲取全部標籤的文本
# print(v)

20.append在當前標籤內部追加一個標籤

# tag = soup.find('body')
# tag.append(soup.find('a'))
# print(soup)
#
# from bs4.element import Tag
# obj = Tag(name='i',attrs={'id': 'it'})
# obj.string = '我是一個新來的'
# tag = soup.find('body')
# tag.append(obj)
# print(soup)

21.insert在當前標籤內部指定位置插入一個標籤

# from bs4.element import Tag
# obj = Tag(name='i', attrs={'id': 'it'})
# obj.string = '我是一個新來的'
# tag = soup.find('body')
# tag.insert(2, obj)
# print(soup)

22. insert_after,insert_before 在當前標籤後面或前面插入

# from bs4.element import Tag
# obj = Tag(name='i', attrs={'id': 'it'})
# obj.string = '我是一個新來的'
# tag = soup.find('body')
# # tag.insert_before(obj)
# tag.insert_after(obj)
# print(soup)

23. replace_with 在當前標籤替換爲指定標籤

# from bs4.element import Tag
# obj = Tag(name='i', attrs={'id': 'it'})
# obj.string = '我是一個新來的'
# tag = soup.find('div')
# tag.replace_with(obj)
# print(soup)

24. 建立標籤之間的關係

# tag = soup.find('div')
# a = soup.find('a')
# tag.setup(previous_sibling=a)
# print(tag.previous_sibling)

25. wrap,用指定標籤把當前標籤包裹起來,括號內的標籤放在當前標籤的外面

# from bs4.element import Tag
# obj1 = Tag(name='div', attrs={'id': 'it'})
# obj1.string = '我是一個新來的'
#
# tag = soup.find('a')
# v = tag.wrap(obj1)
# print(soup)
 
# tag = soup.find('a')
# v = tag.wrap(soup.find('p'))
# print(soup)

26. unwrap,去掉當前標籤,將保留其包裹的標籤

# tag = soup.find('a')
# v = tag.unwrap()
# print(soup)

更多參數官方:http://beautifulsoup.readthedocs.io/zh_CN/v4.4.0/

3、自動登錄抽屜並點贊

import requests

### 發送請求時,帶上headers,不然會遇到防火牆,必定要訪問:https://
# headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0'}
headers={
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36',
    'referer':'https://dig.chouti.com/', # 表示上一次訪問的地址,有些網站須要你先訪問一次才能知道你不是經過request發送的請求
}

# 先訪問主頁
response1 = requests.get(
    url= "https://dig.chouti.com/",
    headers=headers,
)
cookie1 = response1.cookies.get_dict()
print(cookie1)
#{'gpsd': '160d28d416d222dcd6eeb1c1d5ebd268', 'JSESSIONID': 'aaahlyoDbL5GQfrqjq2Lw'}

# 登錄,攜帶第一次訪問網站時返回的cookies
response2 = requests.post(
    url="https://dig.chouti.com/login",
    data={
        'phone': "86155232",
        'password': "123456",
        'oneMonth': ''
    },
    cookies=cookie1,
    headers=headers,
)
print(response2.status_code)
cookie2 = response2.cookies.get_dict()
print(cookie2) # 登錄後又返回一個gpsd,可是這個沒有用,第一個纔是驗證身份用的

# 訪問本身的設置頁面
response3 = requests.get(
    url='https://dig.chouti.com/profile',
    cookies={'gpsd':cookie1.get('gpsd')},
    headers=headers,
)
print(response3.text) 

# 點贊 ,只須要攜帶已經被受權的gpsd便可,第一次的是被受權的
response4 = requests.post(
    url='https://dig.chouti.com/link/vote?linksId=25263971',
    cookies={'gpsd':cookie1.get('gpsd')},
    headers=headers,
)
print(response4.text)
# {"result":{"code":"9999", "message":"推薦成功",
# "data":{"jid":"cdu_55306581825","likedTime":"1553068537532000",
# "lvCount":"8","nick":"查理大夫","uvCount":"1","voteTime":"小於1分鐘前"}}}

4、「破解」微信公衆號

「破解」微信公衆號其實就是使用Python代碼自動實現【登錄公衆號】->【獲取觀衆用戶】-> 【向關注用戶發送消息】。

注:只能向48小時內有互動的粉絲主動推送消息

一、自動登錄

分析對於Web登錄頁面,用戶登錄驗證時僅作了以下操做:

  • 登錄的URL:https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN
  • POST的數據爲:

        {
             'username': 用戶名,
             'pwd': 密碼的MD5值,
             'imgcode': "", 
             'f': 'json'
        }
    注:imgcode是須要提供的驗證碼,默認無需驗證碼,只有在屢次登錄未成功時,才須要用戶提供驗證碼才能登錄

  • POST的請求頭的Referer值,微信後臺用次來檢查是誰發送來的請求
  • 請求發送並登錄成功後,獲取用戶響應的cookie,之後操做其餘頁面時須要攜帶此cookie 
  • 請求發送並登錄成功後,獲取用戶相應的內容中的token

登錄代碼:

import requests
import time
import hashlib


def _password(pwd):
    ha = hashlib.md5()
    ha.update(pwd)
    return ha.hexdigest()

def login():
    
    login_dict = {
        'username': "用戶名",
        'pwd': _password("密碼"),
        'imgcode': "",
        'f': 'json'
    }

    login_res = requests.post(
        url= "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN",
        data=login_dict,
        headers={'Referer': 'https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN'})

    # 登錄成功以後獲取服務器響應的cookie
    resp_cookies_dict = login_res.cookies.get_dict()
    # 登錄成功後,獲取服務器響應的內容
    resp_text = login_res.text
    # 登錄成功後,獲取token
    token = re.findall(".*token=(\d+)", resp_text)[0]

    print resp_text
    print token
    print resp_cookies_dict

login()

登錄成功獲取的相應內容以下:

響應內容:
{"base_resp":{"ret":0,"err_msg":"ok"},"redirect_url":"\/cgi-bin\/home?t=home\/index&lang=zh_CN&token=537908795"}
 
響應cookie:
{'data_bizuin': '3016804678', 'bizuin': '3016804678', 'data_ticket': 'CaoX+QA0ZA9LRZ4YM3zZkvedyCY8mZi0XlLonPwvBGkX0/jY/FZgmGTq6xGuQk4H', 'slave_user': 'gh_5abeaed48d10', 'slave_sid': 'elNLbU1TZHRPWDNXSWdNc2FjckUxalM0Y000amtTamlJOUliSnRnWGRCdjFseV9uQkl5cUpHYkxqaGJNcERtYnM2WjdFT1pQckNwMFNfUW5fUzVZZnFlWGpSRFlVRF9obThtZlBwYnRIVGt6cnNGbUJsNTNIdTlIc2JJU29QM2FPaHZjcTcya0F6UWRhQkhO'}

二、訪問其餘頁面獲取用戶信息

分析用戶管理頁面,經過Pyhton代碼以Get方式訪問此頁面,分析響應到的 HTML 代碼,從中獲取用戶信息:

  • 獲取用戶的URL:https://mp.weixin.qq.com/cgi-bin/user_tag?action=get_all_data&lang=zh_CN&token=登錄時獲取的token
  • 發送GET請求時,須要攜帶登錄成功後獲取的cookie
{'data_bizuin': '3016804678', 'bizuin': '3016804678', 'data_ticket': 'C4YM3zZ...
  • 獲取當前請求的響應的html代碼
  • 經過正則表達式獲取html中的指定內容(Python的模塊Beautiful Soup)
  • 獲取html中每一個用戶的 data-fakeid屬性,該值是用戶的惟一標識,經過它可向用戶推送消息

代碼實現:

import requests
import time
import hashlib
import json
import re

LOGIN_COOKIES_DICT = {}

def _password(pwd):
    ha = hashlib.md5()
    ha.update(pwd)
    return ha.hexdigest()

def login():
    
    login_dict = {
        'username': "用戶名",
        'pwd': _password("密碼"),
        'imgcode': "",
        'f': 'json'
    }

    login_res = requests.post(
        url= "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN",
        data=login_dict,
        headers={'Referer': 'https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN'})

    # 登錄成功以後獲取服務器響應的cookie
    resp_cookies_dict = login_res.cookies.get_dict()
    # 登錄成功後,獲取服務器響應的內容
    resp_text = login_res.text
    # 登錄成功後,獲取token
    token = re.findall(".*token=(\d+)", resp_text)[0]

    return {'token': token, 'cookies': resp_cookies_dict}


def standard_user_list(content):
    content = re.sub('\s*', '', content)
    content = re.sub('\n*', '', content)
    data = re.findall("""cgiData=(.*);seajs""", content)[0]
    data = data.strip()
    while True:
        temp = re.split('({)(\w+)(:)', data, 1)
        if len(temp) == 5:
            temp[2] = '"' + temp[2] + '"'
            data = ''.join(temp)
        else:
            break

    while True:
        temp = re.split('(,)(\w+)(:)', data, 1)
        if len(temp) == 5:
            temp[2] = '"' + temp[2] + '"'
            data = ''.join(temp)
        else:
            break

    data = re.sub('\*\d+', "", data)
    ret = json.loads(data)
    return ret


def get_user_list():

    login_dict = login()
    LOGIN_COOKIES_DICT.update(login_dict)

    login_cookie_dict = login_dict['cookies']
    res_user_list = requests.get(
        url= "https://mp.weixin.qq.com/cgi-bin/user_tag",
        params = {"action": "get_all_data", "lang": "zh_CN", "token": login_dict['token']},
        cookies = login_cookie_dict,
        headers={'Referer': 'https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN'}
    )
    user_info = standard_user_list(res_user_list.text)
    for item in user_info['user_list']:
        print "%s %s " % (item['nick_name'],item['id'],)
    
get_user_list()

三、發送消息

分析給用戶發送消息的頁面,從網絡請求中剖析獲得發送消息的URL,從而使用Python代碼發送消息:

  • 發送消息的URL:https://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response&f=json&token=登錄時獲取的token放在此處&lang=zh_CN
  • 從登錄時相應的內容中獲取:token和cookie
  • 從用戶列表中獲取某個用戶惟一標識: fake_id
  • 封裝消息,併發送POST請求
send_dict = {
    'token': 登錄時獲取的token,
    'lang': "zh_CN",
    'f': 'json',
    'ajax': 1,
    'random': "0.5322618900912392",
    'type': 1,
    'content': 要發送的內容,
    'tofakeid': 用戶列表中獲取的用戶的ID,
    'imgcode': ''
}

  

import requests
import time
import hashlib
import json
import re

LOGIN_COOKIES_DICT = {}

def _password(pwd):
    ha = hashlib.md5()
    ha.update(pwd)
    return ha.hexdigest()

def login():
    
    login_dict = {
        'username': "用戶名",
        'pwd': _password("密碼"),
        'imgcode': "",
        'f': 'json'
    }

    login_res = requests.post(
        url= "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN",
        data=login_dict,
        headers={'Referer': 'https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN'})

    # 登錄成功以後獲取服務器響應的cookie
    resp_cookies_dict = login_res.cookies.get_dict()
    # 登錄成功後,獲取服務器響應的內容
    resp_text = login_res.text
    # 登錄成功後,獲取token
    token = re.findall(".*token=(\d+)", resp_text)[0]

    return {'token': token, 'cookies': resp_cookies_dict}


def standard_user_list(content):
    content = re.sub('\s*', '', content)
    content = re.sub('\n*', '', content)
    data = re.findall("""cgiData=(.*);seajs""", content)[0]
    data = data.strip()
    while True:
        temp = re.split('({)(\w+)(:)', data, 1)
        if len(temp) == 5:
            temp[2] = '"' + temp[2] + '"'
            data = ''.join(temp)
        else:
            break

    while True:
        temp = re.split('(,)(\w+)(:)', data, 1)
        if len(temp) == 5:
            temp[2] = '"' + temp[2] + '"'
            data = ''.join(temp)
        else:
            break

    data = re.sub('\*\d+', "", data)
    ret = json.loads(data)
    return ret


def get_user_list():

    login_dict = login()
    LOGIN_COOKIES_DICT.update(login_dict)

    login_cookie_dict = login_dict['cookies']
    res_user_list = requests.get(
        url= "https://mp.weixin.qq.com/cgi-bin/user_tag",
        params = {"action": "get_all_data", "lang": "zh_CN", "token": login_dict['token']},
        cookies = login_cookie_dict,
        headers={'Referer': 'https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN'}
    )
    user_info = standard_user_list(res_user_list.text)
    for item in user_info['user_list']:
        print "%s %s " % (item['nick_name'],item['id'],)
    

def send_msg(user_fake_id, content='啥也沒發'):

    login_dict = LOGIN_COOKIES_DICT
    
    token = login_dict['token']
    login_cookie_dict = login_dict['cookies']

    send_dict = {
        'token': token,
        'lang': "zh_CN",
        'f': 'json',
        'ajax': 1,
        'random': "0.5322618900912392",
        'type': 1,
        'content': content,
        'tofakeid': user_fake_id,
        'imgcode': ''
    }
   
    send_url = "https://mp.weixin.qq.com/cgi-bin/singlesend?t=ajax-response&f=json&token=%s&lang=zh_CN" % (token,)
    message_list = requests.post(
        url=send_url, 
        data=send_dict, 
        cookies=login_cookie_dict, 
        headers={'Referer': 'https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN'}
    )


get_user_list()
fake_id = raw_input('請輸入用戶ID:')
content = raw_input('請輸入消息內容:')
send_msg(fake_id, content)
發送消息代碼

以上就是「破解」微信公衆號的整個過程,經過Python代碼實現了自動【登錄微信公衆號平臺】【獲取用戶列表】【指定用戶發送消息】。

5、自動登錄示例

import requests
from bs4 import BeautifulSoup

############## 方式一 ##############

# 1. 訪問登錄頁面,獲取 authenticity_token
i1 = requests.get('https://github.com/login')
soup1 = BeautifulSoup(i1.text, features='lxml')
tag = soup1.find(name='input', attrs={'name': 'authenticity_token'})
authenticity_token = tag.get('value')
c1 = i1.cookies.get_dict()
i1.close()

# 1. 攜帶authenticity_token和用戶名密碼等信息,發送用戶驗證
form_data = {
    "authenticity_token": authenticity_token,
    "utf8": "",
    "commit": "Sign in",
    "login": "charliedaifu",
    'password': 'xxxx'
}

i2 = requests.post('https://github.com/session', data=form_data, cookies=c1)
c2 = i2.cookies.get_dict()
print(c2)
print(i2.status_code)

c1.update(c2)
i3 = requests.get('https://github.com/settings/repositories', cookies=c1)

soup3 = BeautifulSoup(i3.text, features='lxml')
list_group = soup3.find(name='div', class_='listgroup')

from bs4.element import Tag

for child in list_group.children:
    if isinstance(child, Tag):
        project_tag = child.find(name='a', class_='mr-1')
        size_tag = child.find(name='small')
        temp = "項目:%s(%s); 項目路徑:%s" % (project_tag.get('href'), size_tag.string if size_tag else '', project_tag.string, )
        print(temp)


"""
############## 方式二 ##############
session = requests.Session()
# 1. 訪問登錄頁面,獲取 authenticity_token
i1 = session.get('https://github.com/login')
soup1 = BeautifulSoup(i1.text, features='lxml')
tag = soup1.find(name='input', attrs={'name': 'authenticity_token'})
authenticity_token = tag.get('value')
c1 = i1.cookies.get_dict()
i1.close()

# 1. 攜帶authenticity_token和用戶名密碼等信息,發送用戶驗證
form_data = {
    "authenticity_token": authenticity_token,
    "utf8": "",
    "commit": "Sign in",
    "login": "wupeiqi@live.com",
    'password': 'xxoo'
}

i2 = session.post('https://github.com/session', data=form_data)
c2 = i2.cookies.get_dict()
c1.update(c2)
i3 = session.get('https://github.com/settings/repositories')

soup3 = BeautifulSoup(i3.text, features='lxml')
list_group = soup3.find(name='div', class_='listgroup')

from bs4.element import Tag

for child in list_group.children:
    if isinstance(child, Tag):
        project_tag = child.find(name='a', class_='mr-1')
        size_tag = child.find(name='small')
        temp = "項目:%s(%s); 項目路徑:%s" % (project_tag.get('href'), size_tag.string if size_tag else '', project_tag.string, )
        print(temp)
"""
GitHub

 

import time

import requests
from bs4 import BeautifulSoup

session = requests.Session()

i1 = session.get(
    url='https://www.zhihu.com/#signin',
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    }
)

soup1 = BeautifulSoup(i1.text, 'lxml')
xsrf_tag = soup1.find(name='input', attrs={'name': '_xsrf'})
xsrf = xsrf_tag.get('value')

current_time = time.time()
i2 = session.get(
    url='https://www.zhihu.com/captcha.gif',
    params={'r': current_time, 'type': 'login'},
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    })

with open('zhihu.gif', 'wb') as f:
    f.write(i2.content)

captcha = input('請打開zhihu.gif文件,查看並輸入驗證碼:')
form_data = {
    "_xsrf": xsrf,
    'password': 'xxooxxoo',
    "captcha": 'captcha',
    'email': '424662508@qq.com'
}
i3 = session.post(
    url='https://www.zhihu.com/login/email',
    data=form_data,
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    }
)

i4 = session.get(
    url='https://www.zhihu.com/settings/profile',
    headers={
        'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36',
    }
)

soup4 = BeautifulSoup(i4.text, 'lxml')
tag = soup4.find(id='rename-section')
nick_name = tag.find('span',class_='name').string
print(nick_name)
知乎

 

import re
import json
import base64

import rsa
import requests


def js_encrypt(text):
    b64der = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB'
    der = base64.standard_b64decode(b64der)

    pk = rsa.PublicKey.load_pkcs1_openssl_der(der)
    v1 = rsa.encrypt(bytes(text, 'utf8'), pk)
    value = base64.encodebytes(v1).replace(b'\n', b'')
    value = value.decode('utf8')

    return value


session = requests.Session()

i1 = session.get('https://passport.cnblogs.com/user/signin')
rep = re.compile("'VerificationToken': '(.*)'")
v = re.search(rep, i1.text)
verification_token = v.group(1)

form_data = {
    'input1': js_encrypt('wptawy'),
    'input2': js_encrypt('asdfasdf'),
    'remember': False
}

i2 = session.post(url='https://passport.cnblogs.com/user/signin',
                  data=json.dumps(form_data),
                  headers={
                      'Content-Type': 'application/json; charset=UTF-8',
                      'X-Requested-With': 'XMLHttpRequest',
                      'VerificationToken': verification_token}
                  )

i3 = session.get(url='https://i.cnblogs.com/EditDiary.aspx')

print(i3.text)
博客園

 

import requests


# 第一步:訪問登錄頁,拿到X_Anti_Forge_Token,X_Anti_Forge_Code
# 一、請求url:https://passport.lagou.com/login/login.html
# 二、請求方法:GET
# 三、請求頭:
#    User-agent
r1 = requests.get('https://passport.lagou.com/login/login.html',
                 headers={
                     'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
                 },
                 )

X_Anti_Forge_Token = re.findall("X_Anti_Forge_Token = '(.*?)'", r1.text, re.S)[0]
X_Anti_Forge_Code = re.findall("X_Anti_Forge_Code = '(.*?)'", r1.text, re.S)[0]
print(X_Anti_Forge_Token, X_Anti_Forge_Code)
# print(r1.cookies.get_dict())
# 第二步:登錄
# 一、請求url:https://passport.lagou.com/login/login.json
# 二、請求方法:POST
# 三、請求頭:
#    cookie
#    User-agent
#    Referer:https://passport.lagou.com/login/login.html
#    X-Anit-Forge-Code:53165984
#    X-Anit-Forge-Token:3b6a2f62-80f0-428b-8efb-ef72fc100d78
#    X-Requested-With:XMLHttpRequest
# 四、請求體:
# isValidate:true
# username:15131252215
# password:ab18d270d7126ea65915c50288c22c0d
# request_form_verifyCode:''
# submit:''
r2 = requests.post(
    'https://passport.lagou.com/login/login.json',
    headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
        'Referer': 'https://passport.lagou.com/login/login.html',
        'X-Anit-Forge-Code': X_Anti_Forge_Code,
        'X-Anit-Forge-Token': X_Anti_Forge_Token,
        'X-Requested-With': 'XMLHttpRequest'
    },
    data={
        "isValidate": True,
        'username': '15131255089',
        'password': 'ab18d270d7126ea65915c50288c22c0d',
        'request_form_verifyCode': '',
        'submit': ''
    },
    cookies=r1.cookies.get_dict()
)
print(r2.text)
拉勾網

 

文章轉載自http://www.cnblogs.com/wupeiqi/articles/5354900.html

相關文章
相關標籤/搜索