python自動(dòng)化操作神器pyautogui使用

python中可以使用 selenium庫(kù)實(shí)現(xiàn)對(duì)瀏覽器的自動(dòng)化操作谴仙,但selenium庫(kù)能操作的還是瀏覽器對(duì)象
今天我們來(lái)聊一聊如何在桌面實(shí)現(xiàn)自動(dòng)化操作坞靶。與瀏覽器頁(yè)面自動(dòng)化操作類似辽剧,桌面自動(dòng)化操作也是需要定位鼠標(biāo)在桌面的位置排截,然后根據(jù)定位的位置執(zhí)行對(duì)應(yīng)的操作娱节。
pyautogui是一個(gè)使用python的跨平臺(tái)的操作鼠標(biāo)和鍵盤的模塊挠蛉,非常方便使用。還支持一些簡(jiǎn)單的圖像識(shí)別相關(guān)操作
文末附贈(zèng)pyautogui圖像識(shí)別無(wú)法跨分辨率解決方案

安裝

pip install pyautogui

提示 ModuleNotFoundError: No module named 'win32api' 需要安裝pip install pypiwin32

提示import win32api, win32con ImportError: DLL load failed: 找不到指定的程序肄满。

需要 pip install pywin32==227 不行就 pip install pywin32==223

安裝如果出現(xiàn)缺少模塊 pyHook https://zhuanlan.zhihu.com/p/143676206

使用

前置參數(shù)

import pyautogui 
# 停頓功能 
pyautogui.PAUSE = 1 # 調(diào)用在執(zhí)行動(dòng)作后暫停的秒數(shù)谴古,只能在執(zhí)行一些pyautogui動(dòng)作后才能使用,建議用time.sleep
# 自動(dòng) 防故障功能
pyautogui.FAILSAFE = True # 啟用自動(dòng)防故障功能悄窃,左上角的坐標(biāo)為(0讥电,0),將鼠標(biāo)移到屏幕的左上角轧抗,來(lái)拋出failSafeException異常

鼠標(biāo)操作

獲取屏幕的寬度和高度

width, height = pyautogui.size() # 獲取屏幕的寬度和高度
print(width, height)

獲取鼠標(biāo)當(dāng)前位置

currentMouseX, currentMouseY = pyautogui.position() # 鼠標(biāo)當(dāng)前位置
print(currentMouseX, currentMouseY)

鼠標(biāo)移動(dòng)類操作

# pyautogui.moveTo(x,y,持續(xù)時(shí)間) 在持續(xù)時(shí)間內(nèi) 將光標(biāo)移動(dòng)到目標(biāo)位置(x,y)
pyautogui.moveTo(100, 100, duration=0.25) # 移動(dòng)到 (100,100)

#pyautogui.moveRel(xOffset,yxOffset,持續(xù)時(shí)間) 在持續(xù)時(shí)間內(nèi) 將光標(biāo)偏移 距離原始位置 xOffset,yxOffset 的位置
pyautogui.moveRel(50, 0, duration=0.25) # 從當(dāng)前位置右移50像素

# 實(shí)現(xiàn)拖拽效果
pyautogui.mouseDown(740,73)  #鼠標(biāo)按下指定位置
pyautogui.moveRel(100,0,2)  #移動(dòng)/可以使用其他移動(dòng)方法
pyautogui.mouseUp()     # 鼠標(biāo)抬起
#或者
pyautogui.dragTo(100,300,duration=1)   
#或者
pyautogui.dragRel(100,300,duration=4) 

鼠標(biāo)滾動(dòng)類操作

# scroll函數(shù)控制鼠標(biāo)滾輪的滾動(dòng)恩敌,amount_to_scroll參數(shù)表示滾動(dòng)的格數(shù)。正數(shù)則頁(yè)面向上滾動(dòng)横媚,負(fù)數(shù)則向下滾動(dòng)
# pyautogui.scroll(clicks=amount_to_scroll, x=moveToX, y=moveToY)
# 默認(rèn)從當(dāng)前光標(biāo)位置進(jìn)行滑動(dòng)  amount_to_scroll是個(gè)數(shù)字 數(shù)字太小效果可能不明顯, 正數(shù)表示往上劃 負(fù)數(shù)表示往下化
pyautogui.scroll(500, 20, 2)
pyautogui.scroll(100) # 向上滾動(dòng)100格
pyautogui.scroll(-100) # 向下滾動(dòng)100格
pyautogui.scroll(100, x=100, y=100) # 移動(dòng)到(100, 100)位置再向上滾動(dòng)100格

鼠標(biāo)點(diǎn)擊類操作

# pyautogui.click(x,y,clicks=點(diǎn)擊次數(shù),interval=每次點(diǎn)擊間隔頻率,button=可以是left表示左擊 可以是right表示右擊 可以是middle表示中擊)
pyautogui.click(10, 20, 2, 0.25, button='left')
pyautogui.click(x=100, y=200, duration=2) # 先移動(dòng)到(100, 200)再單擊
pyautogui.click() # 鼠標(biāo)當(dāng)前位置點(diǎn)擊一下
pyautogui.doubleClick() # 鼠標(biāo)當(dāng)前位置左擊兩下
pyautogui.doubleClick(x=100, y=150, button="left") # 鼠標(biāo)在(100纠炮,150)位置左擊兩下
pyautogui.tripleClick() # 鼠標(biāo)當(dāng)前位置左擊三下
pyautogui.rightClick(10,10)   # 指定位置,雙擊右鍵
pyautogui.middleClick(10,10)  # 指定位置灯蝴,雙擊中鍵

鍵盤操作

# 相關(guān)操作
# pyautogui.typewrite(要輸入的字符只能是英文,interval=輸入每個(gè)字符的間隔頻率)
pyautogui.typewrite('python', 1)
# typewrite 還可以傳入單字母的列表
# 運(yùn)行下面代碼恢口,編輯器里面就會(huì)輸出 python 之后換行。
pyautogui.typewrite(['p','y','t','h','o','n','enter'])   

# pyautogui.keyDown():模擬按鍵按下
# pyautogui.keyUP():模擬按鍵松開
# pyautogui.press(鍵盤按鍵字母)  模擬一次按鍵過(guò)程穷躁,即 keyDown 和 keyUP 的組合 按下指定的鍵盤按鍵
# pyautogui.hotkey("ctrl","a")  實(shí)現(xiàn)組合鍵功能

# 按住 shift 按鍵耕肩,然后再按住 1 按鍵,就可以了。用 pyautogui 控制就是
pyautogui.keyDown('shift')    
pyautogui.press('1')    
pyautogui.keyUp('shift')  


# 輸入中文字符的方法  借用 pyperclip模塊
import pyperclip
pyperclip.copy("要書寫的字符串")  #復(fù)制字符串
time.sleep(2)
pyautogui.hotkey("ctrl","v") #實(shí)現(xiàn)復(fù)制


# pyautogui.KEYBOARD_KEYS數(shù)組中就是press()猿诸,keyDown()婚被,keyUp()和hotkey()函數(shù)可以輸入的按鍵名稱
pyautogui.KEYBOARD_KEYS = ['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.',
              '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@',
              '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
              'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
              'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace', 'browserback',
              'browserfavorites', 'browserforward', 'browserhome', 'browserrefresh', 'browsersearch',
              'browserstop', 'capslock', 'clear', 'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal',
              'del', 'delete', 'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10',
              'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', 'f21', 'f22',
              'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'final', 'fn', 'hanguel', 'hangul',
              'hanja', 'help', 'home', 'insert', 'junja', 'kana', 'kanji', 'launchapp1', 'launchapp2',
              'launchmail', 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack',
              'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8', 'num9',
              'numlock', 'pagedown', 'pageup', 'pause', 'pgdn', 'pgup', 'playpause', 'prevtrack', 'print',
              'printscreen', 'prntscrn', 'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select',
              'separator', 'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab',
              'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen', 'command',
              'option', 'optionleft', 'optionright']

彈窗操作

import pyautogui
 
# 顯示一個(gè)簡(jiǎn)單的帶文字和OK按鈕的消息彈窗。用戶點(diǎn)擊后返回button的文字梳虽。
pyautogui.alert(text='', title='', button='OK')
b = pyautogui.alert(text='要開始程序么址芯?', title='請(qǐng)求框', button='OK')
print(b) # 輸出結(jié)果為OK
 
# 顯示一個(gè)簡(jiǎn)單的帶文字、OK和Cancel按鈕的消息彈窗窜觉,用戶點(diǎn)擊后返回被點(diǎn)擊button的文字谷炸,支持自定義數(shù)字、文字的列表禀挫。
pyautogui.confirm(text='', title='', buttons=['OK', 'Cancel']) # OK和Cancel按鈕的消息彈窗
pyautogui.confirm(text='', title='', buttons=range(10)) # 10個(gè)按鍵0-9的消息彈窗
a = pyautogui.confirm(text='', title='', buttons=range(10))
print(a) # 輸出結(jié)果為你選的數(shù)字
 
# 可以輸入的消息彈窗旬陡,帶OK和Cancel按鈕。用戶點(diǎn)擊OK按鈕返回輸入的文字语婴,點(diǎn)擊Cancel按鈕返回None季惩。
pyautogui.prompt(text='', title='', default='')
 
# 樣式同prompt(),用于輸入密碼腻格,消息用*表示。帶OK和Cancel按鈕啥繁。用戶點(diǎn)擊OK按鈕返回輸入的文字菜职,點(diǎn)擊Cancel按鈕返回None。
pyautogui.password(text='', title='', default='', mask='*')

圖像操作

import pyautogui
im = pyautogui.screenshot() # 返回屏幕的截圖旗闽,是一個(gè)Pillow的image對(duì)象
im.save('屏幕截圖.png') #保存圖片
# 或者
im = pyautogui.screenshot('屏幕截圖.png') # 截全屏并設(shè)置保存圖片的位置和名稱
print(im) # 打印圖片的屬性

# 不截全屏酬核,截取區(qū)域圖片。截取區(qū)域region參數(shù)為:左上角XY坐標(biāo)值适室、寬度和高度
pyautogui.screenshot('屏幕截圖.png', region=(0, 0, 300, 400))
 

# 獲得文件圖片在現(xiàn)在的屏幕上面的坐標(biāo)嫡意,返回的是一個(gè)元組(top, left, width, height)
# 如果截圖沒找到,pyautogui.locateOnScreen()函數(shù)返回None
a = pyautogui.locateOnScreen(r'目標(biāo)圖片路徑')
print(a) # 打印結(jié)果為Box(left=0, top=0, width=300, height=400)
x, y = pyautogui.center(a) # 獲得文件圖片在現(xiàn)在的屏幕上面的中心坐標(biāo)
print(x, y) # 打印結(jié)果為150 200
# 或者
x, y = pyautogui.locateCenterOnScreen(r'目標(biāo)圖片路徑') # 這步與上面的四行代碼作用一樣
print(x, y) # 打印結(jié)果為150 200
 
# 匹配屏幕所有與目標(biāo)圖片的對(duì)象捣辆,可以用for循環(huán)和list()輸出
for pos in pyautogui.locateAllOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png'):
  print(pos)
# 打印結(jié)果為Box(left=0, top=0, width=300, height=400)
a = list(pyautogui.locateAllOnScreen(r'C:\Users\ZDH\Desktop\PY\region_screenshot.png'))
print(a) # 打印結(jié)果為[Box(left=0, top=0, width=300, height=400)]

注意:pyautogui的圖像識(shí)別是模板匹配算法 無(wú)法跨分辨率識(shí)別(圖片放大縮小就無(wú)法識(shí)別) 提供以下圖像識(shí)別算法

# -*- coding: utf-8 -*-
"""
使用需求:
    需要安裝 airtest  pip install  airtest  -i https://mirrors.aliyun.com/pypi/simple/
    運(yùn)行時(shí)如果出現(xiàn)以下錯(cuò)誤:  
            import win32api
        ImportError: DLL load failed: 找不到指定的程序蔬螟。
    重新安裝win32api版本
        pip install pywin32==227   # 安裝 227版本
        不行的話再試試
        pip install pywin32==223  # 安裝 223版本
       
"""


import sys
import types
from copy import deepcopy
from airtest import aircv
from airtest.aircv import cv2
from airtest.aircv.template_matching import TemplateMatching
from airtest.core.cv import MATCHING_METHODS, Predictor
from airtest.core.error import InvalidMatchingMethodError
from airtest.core.helper import logwrap, G
from airtest.core.win.screen import screenshot
from airtest.utils.transform import TargetPos
from six import PY3
from airtest.core.settings import Settings as ST  # noqa

# # -*- encoding=utf8 -*-
import logging
logger = logging.getLogger("airtest")
logger.setLevel(logging.ERROR)
# 日志級(jí)別有[DEBUG]、[INFO]汽畴、[WARNING] 和 [ERROR]

class Template(object):
    """
    picture as touch/swipe/wait/exists target and extra info for cv match
    filename: pic filename
    target_pos: ret which pos in the pic
    record_pos: pos in screen when recording
    resolution: screen resolution when recording
    rgb: 識(shí)別結(jié)果是否使用rgb三通道進(jìn)行校驗(yàn).
    scale_max: 多尺度模板匹配最大范圍.
    scale_step: 多尺度模板匹配搜索步長(zhǎng).
    """

    def __init__(self, filename, threshold=None, target_pos=TargetPos.MID, record_pos=None, resolution=(), rgb=False, scale_max=800, scale_step=0.005):
        self.filename = filename
        # self.filename =os.path.join(Settings.Picture_Path,filename)
        self._filepath = None
        self.threshold = threshold or ST.THRESHOLD
        self.target_pos = target_pos
        self.record_pos = record_pos
        self.resolution = resolution
        self.rgb = rgb
        self.scale_max = scale_max
        self.scale_step = scale_step

    @property
    def filepath(self):

        return self.filename

    def __repr__(self):
        filepath = self.filepath if PY3 else self.filepath.encode(sys.getfilesystemencoding())
        return "Template(%s)" % filepath

    def match_in(self, screen):
        match_result = self._cv_match(screen)
        G.LOGGING.debug("match result: %s", match_result)
        if not match_result:
            return None
        focus_pos = TargetPos().getXY(match_result, self.target_pos)
        return focus_pos

    def match_all_in(self, screen):
        image = self._imread()
        image = self._resize_image(image, screen, ST.RESIZE_METHOD)
        return self._find_all_template(image, screen)

    @logwrap
    def _cv_match(self, screen):
        # in case image file not exist in current directory:
        ori_image = self._imread()
        image = self._resize_image(ori_image, screen, ST.RESIZE_METHOD)
        ret = None
        for method in ST.CVSTRATEGY:
            # get function definition and execute:
            func = MATCHING_METHODS.get(method, None)
            if func is None:
                raise InvalidMatchingMethodError("Undefined method in CVSTRATEGY: '%s', try 'kaze'/'brisk'/'akaze'/'orb'/'surf'/'sift'/'brief' instead." % method)
            else:
                if method in ["mstpl", "gmstpl"]:
                    ret = self._try_match(func, ori_image, screen, threshold=self.threshold, rgb=self.rgb, record_pos=self.record_pos,
                                            resolution=self.resolution, scale_max=self.scale_max, scale_step=self.scale_step)
                else:
                    ret = self._try_match(func, image, screen, threshold=self.threshold, rgb=self.rgb)
            if ret:
                break
        return ret

    @staticmethod
    def _try_match(func, *args, **kwargs):
        G.LOGGING.debug("try match with %s" % func.__name__)
        try:
            ret = func(*args, **kwargs).find_best_result()
        except aircv.NoModuleError as err:
            G.LOGGING.warning("'surf'/'sift'/'brief' is in opencv-contrib module. You can use 'tpl'/'kaze'/'brisk'/'akaze'/'orb' in CVSTRATEGY, or reinstall opencv with the contrib module.")
            return None
        except aircv.BaseError as err:
            G.LOGGING.debug(repr(err))
            return None
        else:
            return ret

    def _imread(self):
        return aircv.imread(self.filepath)

    def _find_all_template(self, image, screen):
        return TemplateMatching(image, screen, threshold=self.threshold, rgb=self.rgb).find_all_results()

    def _find_keypoint_result_in_predict_area(self, func, image, screen):
        if not self.record_pos:
            return None
        # calc predict area in screen
        image_wh, screen_resolution = aircv.get_resolution(image), aircv.get_resolution(screen)
        xmin, ymin, xmax, ymax = Predictor.get_predict_area(self.record_pos, image_wh, self.resolution, screen_resolution)
        # crop predict image from screen
        predict_area = aircv.crop_image(screen, (xmin, ymin, xmax, ymax))
        if not predict_area.any():
            return None
        # keypoint matching in predicted area:
        ret_in_area = func(image, predict_area, threshold=self.threshold, rgb=self.rgb)
        # calc cv ret if found
        if not ret_in_area:
            return None
        ret = deepcopy(ret_in_area)
        if "rectangle" in ret:
            for idx, item in enumerate(ret["rectangle"]):
                ret["rectangle"][idx] = (item[0] + xmin, item[1] + ymin)
        ret["result"] = (ret_in_area["result"][0] + xmin, ret_in_area["result"][1] + ymin)
        return ret

    def _resize_image(self, image, screen, resize_method):
        """模板匹配中旧巾,將輸入的截圖適配成 等待模板匹配的截圖."""
        # 未記錄錄制分辨率,跳過(guò)
        if not self.resolution:
            return image
        screen_resolution = aircv.get_resolution(screen)
        # 如果分辨率一致忍些,則不需要進(jìn)行im_search的適配:
        if tuple(self.resolution) == tuple(screen_resolution) or resize_method is None:
            return image
        if isinstance(resize_method, types.MethodType):
            resize_method = resize_method.__func__
        # 分辨率不一致則進(jìn)行適配鲁猩,默認(rèn)使用cocos_min_strategy:
        h, w = image.shape[:2]
        w_re, h_re = resize_method(w, h, self.resolution, screen_resolution)
        # 確保w_re和h_re > 0, 至少有1個(gè)像素:
        w_re, h_re = max(1, w_re), max(1, h_re)
        # 調(diào)試代碼: 輸出調(diào)試信息.
        G.LOGGING.debug("resize: (%s, %s)->(%s, %s), resolution: %s=>%s" % (
                        w, h, w_re, h_re, self.resolution, screen_resolution))
        # 進(jìn)行圖片縮放:
        image = cv2.resize(image, (w_re, h_re))
        return image

if __name__ == '__main__':
    """
    用法:
    res = Template(目標(biāo)圖片路徑,threshold=匹配閾值,target_pos=可以是123456789 分別對(duì)應(yīng)圖片的九個(gè)點(diǎn)).match_in(screenshot(None))
    """
    res = Template("pppp.png",threshold=0.8,target_pos=5).match_in(screenshot(None))
    print(res)


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市罢坝,隨后出現(xiàn)的幾起案子廓握,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隙券,死亡現(xiàn)場(chǎng)離奇詭異男应,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)是尔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門殉了,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人拟枚,你說(shuō)我怎么就攤上這事薪铜。” “怎么了恩溅?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵隔箍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我脚乡,道長(zhǎng)蜒滩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任奶稠,我火速辦了婚禮俯艰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锌订。我一直安慰自己竹握,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布辆飘。 她就那樣靜靜地躺著啦辐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蜈项。 梳的紋絲不亂的頭發(fā)上芹关,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音紧卒,去河邊找鬼侥衬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛跑芳,可吹牛的內(nèi)容都是我干的浇冰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼聋亡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肘习!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起坡倔,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤漂佩,失蹤者是張志新(化名)和其女友劉穎脖含,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體投蝉,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡统求,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年懊蒸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚎莉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片优烧。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖庸娱,靈堂內(nèi)的尸體忽然破棺而出着绊,到底是詐尸還是另有隱情,我是刑警寧澤熟尉,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布归露,位于F島的核電站,受9級(jí)特大地震影響斤儿,放射性物質(zhì)發(fā)生泄漏剧包。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一往果、第九天 我趴在偏房一處隱蔽的房頂上張望疆液。 院中可真熱鬧,春花似錦陕贮、人聲如沸枚粘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至福也,卻和暖如春局骤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暴凑。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工峦甩, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人现喳。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓凯傲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嗦篱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冰单,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容