65.1-动态网页处理-PhantomJS和Selenium简单应用

要学会新东西,要不断进步,就必须放低自己的姿势!

总结:

  1. 显示等待: 满足条件后 ,才会处理网页;
    隐示等待: 设置一个等待时间;
  2. 注意: 搜索框 是元组
    element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located( # 元素加载到DOM,但是不保证他是可见的;
    (By.ID, "inp-query") # 找搜索框 是 元组
    )
  3. 显式等待比隐式等待更节约执行时间,因此更推荐使用显式等待方式判断页面元素是否存在

动态网页处理

很多网站都采用AJAX技术、SPA技术,部分内容都是异步动态加载的。可以提高用户体验,减少不必要的流量,方便CDN加速等。(大部分的网页,尤其是手机)

但是,对于爬虫程序爬取到的HTML页面相当于页面模板了,动态内容不在其中。
解决办法之一,如果能构造一个包含JS引擎的浏览器,让它加载网页并和网站交互,我们编程从这个浏览器获取内容包括动态内容。这个浏览器不需要和用户交互的界面,只要能支持HTTP、HTTPS协议和服务器端交互,能解析HTML、CSS、JS就行了

1. PhantomJS

它是一个headless无头浏览器,支持Javascript。可以运行在Windows、Linux、Mac OS等。
所谓无头浏览器,就是包含Js引擎、浏览器排版引擎等核心组件,但是没有和用户交互的界面的浏览器。

官网 http://phantomjs.org/
官方文档 http://phantomjs.org/
下载 http://phantomjs.org/
下载对应操作系统的Phantomjs,解压缩就可以使用 ;

测试:
确定是否安装成功;

// test.js
"use strict";
console.log('hello world');
phantom.exit();

$ phantomjs-2.1.1-windows\bin\phantomjs.exe test.js
hello world   # 成功运行;

# 自带exmple试运行;
$ phantomjs-2.1.1-windows\bin\phantomjs.exe phantomjs-2.1.1-windows\examples\hello.js
Hello, world!

$ phantomjs-2.1.1-windows\bin\phantomjs.exe phantomjs-2.1.1-windows\examples\version.js
using PhantomJS version 2.1.1

2. Selenium

它是一个WEB自动化测试工具。它可以直接运行在浏览器中,支持主流的浏览器,包括PhantomJS(无界面浏览器)。 动作测试:

官网 https://www.seleniumhq.org/

安装
$ pip install selenium

WebDriver 可以看一下


chrom浏览器的web driverchromedriver.exe),可以在下面网址访问:
http://npm.taobao.org/mirrors/chromedriver/
firefox(火狐浏览器)的web driver (geckodriver.exe)在这里访问:
https://github.com/mozilla/geckodriver/releases

其他浏览器驱动可以见下面列表:
Edge:https://developer.microsoft.com/en-us/micrsosft-edage/tools/webdriver
Safari:https://webkit.org/blog/6900/webdriver-support-in-safari-10/

部分Chromedriver支持的Chrome版本对照表:

chromedriver版本 支持的Chrome版本
v2.41 v67-69
v2.40 v66-68
v2.39 v66-68
v2.38 v65-67
v2.37 v64-66
v2.36 v63-65
v2.35 v62-64
v2.34 v61-63
v2.33 v60-62
v2.32 v59-61
v2.31 v58-60
v2.30 v58-60
v2.29 v56-58
v2.28 v55-57
v2.27 v54-56
v2.26 v53-55
v2.25 v53-55
v2.24 v52-54
v2.23 v51-53
v2.22 v49-52
v2.21 v46-50

3. 开发实战

不同浏览器都会提供操作的接口,Selenium就是使用这些接口来操作浏览器

Selenium最核心的对象就是webdriver,通过它就可以操作浏览器、截图、HTTP访问、解析HTML等。


from selenium.webdriver import PhantomJS

driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.set_window_size(1280,1080)
driver.get('https://www.baidu.com/?tn=78000241_5_hao_pg')

driver.save_screenshot('F:/test/screen-baidu.png')
#----------------------------------------------------------
# 一般还是使用无头浏览器,忽略警告;
UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
  warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '  

1. 处理异步请求

bing的查询结果是通过异步请求返回结果,所以,直接访问页面不能直接获取到搜索结果。


. 定位页面中的内容是否返回成功

from urllib import parse
from selenium.webdriver import PhantomJS
import datetime, time, random

# #如果没有在环境变量指定PhantomJS位置
driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.set_window_size(1280,1080)

# 保存图片;
def savepic():
    basepath = 'F:/test/'
    filename = "{:%Y%m%d%H%M%S}-{:03}.png".format(datetime.datetime.now(), random.randint(1,100))
    driver.save_screenshot(basepath+filename)
    # 生成页面快照并保存

# 模拟浏览器输入网址;
url = 'https://cn.bing.com/search?q=%E9%A9%AC%E5%93%A5%E6%95%99%E8%82%B2'  #自动转的;
# url = 'https://cn.bing.com/search?' + parse.urlencode({'q':'马哥教育'})   # parse.urlencode转字符;
driver.get(url)  # get方法会一直等到页面加载,然后才会继续执行程序,通常测试会在这里选择time.sleep(2)

MAXRETRIES = 5
for i in range(MAXRETRIES):
    try:
        ele = driver.find_element_by_id('b_results')
        print(i, ele.is_displayed())   # 元素看不看得见;
        if not ele.is_displayed():
            time.sleep(1)
            continue
        savepic()
        # break  # 正常加break;   
    except Exception as e:
        print(type(e), e)
        print('--------------------')

driver.quit()
# ----------------------------------------
0 False
1 True      # 页面内容返回成功;
2 True
3 True
4 True

可能结果未必能看到,说明数据回来了,而且组织好了,但是没有显示出来。
可以增加判断元素是否显示的代码,直到等待的数据呈现在页面上;

2. 下拉框处理

Selenium专门提供了Select类来处理网页中的下拉框(下拉一次,整个页面重新刷新一次,效率低下)

不过下拉框用的页面越来越少了,本次使用 https://www.oschina.net/search?scope=project&q=python

select 下拉框的处理
select下拉框

from disk cache或者from memory cache又是在什么情况下会出现呢?

从字面意思不难理解,这都是浏览器的一种缓存机制。disk 是从硬盘中读取资源,而 memory 则是从内存中获取资源,两者的区别就是内存和硬盘的区别:memory 中的资源是临时的,当关闭或者刷新页面后就会丢失;而 disk 是存在硬盘上的,可以从文件夹中找到。

那是不是 memory 中的资源等下载加载页面的时候又要从服务器获取呢?其实不然,memory 中的资源其实也同时会存在 disk 中,所以下一次加载,浏览器会优先从 disk 中检索



重新刷新请求,说明 disk cache 是在服务器中重新下载的;

表单控件select
from urllib import parse
from selenium.webdriver import PhantomJS
from selenium.webdriver.support.ui import Select    # 在 webdriver.support.ui 下找 Select;

import datetime, time, random

# #如果没有在环境变量指定PhantomJS位置
driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.set_window_size(1280,1080)

# 保存图片;
def savepic():
    basepath = 'F:/test/'
    filename = "{:%Y%m%d%H%M%S}-{:03}.png".format(datetime.datetime.now(), random.randint(1,100))
    driver.save_screenshot(basepath+filename)
    # 生成页面快照并保存

# 模拟浏览器输入网址;
url = 'https://www.oschina.net/search?scope=project'
# url = 'https://cn.bing.com/search?' + parse.urlencode({'q':'马哥教育'})   # parse.urlencode转字符;
driver.get(url)  # get方法会一直等到页面加载,然后才会继续执行程序,通常测试会在这里选择time.sleep(2)
print(1, driver.current_url)
savepic()

# 模拟select 框 怎么使用;
sel = driver.find_element_by_name('tag1')
ele = Select(sel)
ele.select_by_value('309')
# ele.select_by_index(1)

print(2, driver.current_url)
savepic()
driver.quit()

3. 模拟键盘操作(模拟登陆)

web driver提供了一些列find方法, 用户获取一个网页中的元素。元素对象可以使用send_keys模拟键盘输入。

oschina的登录页, 登录成功后会跳转到首页, 首页右上角会显示会员信息, 如果未登录, 无此信息。


在浏览器中 模拟登录过程

分别 有: 打开登录页截图;输入账户截图;登陆成功 截图,拿到cookies ,可以随时登录;

from urllib import parse
from selenium.webdriver import PhantomJS
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.keys import Keys

import datetime, time, random

# #如果没有在环境变量指定PhantomJS位置
driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.set_window_size(1280,1080)

# 保存图片;
def savepic():
    basepath = 'F:/test/'
    filename = "{:%Y%m%d%H%M%S}-{:03}.png".format(datetime.datetime.now(), random.randint(1,100))
    driver.save_screenshot(basepath+filename)
    # 生成页面快照并保存

# 模拟浏览器登录网址;
url = 'https://www.oschina.net/home/login'
# url = 'https://cn.bing.com/search?' + parse.urlencode({'q':'马哥教育'})   # parse.urlencode转字符;
driver.get(url)  # get方法会一直等到页面加载,然后才会继续执行程序,通常测试会在这里选择time.sleep(2)
print(1, driver.current_url)
savepic()   # 打开登录页截图;

# 模拟select 框 怎么使用;
username = driver.find_element_by_name('username')
username.send_keys('')
username = driver.find_element_by_name('password')
username.send_keys('')
# driver.find_element_by_class_name()

savepic()  # 输入账户截图
password.send_keys(Keys.ENTER)

time.sleep(1)
savepic()  # 登陆成功 截图  或者 加上一个验证是否有 退出按钮的 验证;
print(2, driver.current_url)

cookies = driver.get_cookies()  # 
print(cookies,type(cookies))    # 会有key : oscpid

driver.quit()
#----------------------------------
登录成功 会有 oscpid;


获得cookies 登录后 爬取页面
# 获得cookies 登录后 爬取页面
import requests
from requests.cookies import RequestsCookieJar
from fake_useragent import UserAgent

headers = {'User-agent':UserAgent().random}

# no cookies
response = requests.request('GET', url, headers=headers)
text = response.text
print(response.url)  # url中有 login 是未登录状态;

print('==========================================')
# cookies   # 凑cookies 字典;
jar = RequestsCookieJar()
for cookies in cookies:
    jar.set(cookies.get('name'), cookies.get=('value'))  # 凑cookies 字典;

response = requests.request('GET', url, headers=headers, cookies=jar)
text = response.text
print(response.url)   # url中没有 login登陆成功

# 保存登录后的html
with open('./cnblog-html.html','w' , encoding='UTF-8') as f:
    f.write(text)

验证码的问题 不是重点;要看AI模型的成功率;

4. 页面等待技术

越来越多的页面使用Ajax这样的异步加载技术,这就会导致代码中要访问的页面元素,还没有被加载就被访问了(转圈),抛出异常。

方法1 线程休眠

使用time.sleep(n) 来等待数据加载。
配合循环一直等到数据被加载完成,可以解决很多页面动态加载或加载慢的问题。当然可以设置一个最大重试次数,以免一直循环下去。参看本文"处理异步请求”

方法2 Selenium等待

Selenium的等待分为:显示等待 和 隐式等待
隐式等待,等待特定的时间
显式等待,指定一个条件,一直等到这个条件成立后继续执行,也可以设置超时时间,超时会抛异常

参考:https://www.selenium.dev/documentation/en/

# 官网案例:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import presence_of_element_located

#This example requires Selenium WebDriver 3.13 or newer
with webdriver.Firefox() as driver:
    wait = WebDriverWait(driver, 10)
    driver.get("https://google.com/ncr")
    driver.find_element(By.NAME, "q").send_keys("cheese" + Keys.RETURN)
    first_result = wait.until(presence_of_element_located(By.CSS_SELECTOR, "h3>div"))
    print(first_result.get_attribute("textContent"))
  

#-------------------------------------------------------------------------------------------
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.expected_conditions import EC

import datetime, time, random

# #如果没有在环境变量指定PhantomJS位置
driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.set_window_size(1280,1080)


# 保存图片;
def savepic():
    basepath = 'F:/test/'
    filename = "{:%Y%m%d%H%M%S}-{:03}.png".format(datetime.datetime.now(), random.randint(1,100))
    driver.save_screenshot(basepath+filename)
    # 生成页面快照并保存

url = ""
driver.get(url)
driver.find_element(By.ID, 'inp-qury')

try:
    element = WebDriverWait(driver, 10) .until(
        EC.presence_of_element_locate(  # 元素加载到DOM,但是不保证他是可见的;
            (By.ID, "myDynamicElement")
        )
    )
finally:
    driver.quit()

表单

expected_conditionsn内置条件 说明
title_is 判断当前页面的title是否精确等于预期
title_contains 判断当前页面的title是否包含预期字符串
presence_of_element_located 判断某个元素是否被加到了dom树里,并不代表该元素一定可见
visibility_of_element_located 判断某个元素是否可见。可见代表元素非隐藏,并且元素的宽和高都不等于0
visibility_of 跟上面的方法做一样的事情,只是上面的方法要传入locator,这个方法直接传定位到的element就好了
presence_of_all_elements_located 判断是否至少有1个元素存在于dom树中。举个例子,如果页面上有n个元素的class都是'column-md-3',那么只要有1个元素存在,这个方法就返回True
text_to_be_present_in_element 判断某个元素中的text是否包含了预期的字符串
text_to_be_present_in_element_value 判断某个元素中的value属性是否包含了预期的字符串
frame_to_be_available_and_switch_to_it 判断该frame是否可以switch进去, 如果可以的话, 返回True 且switch进去, 否则返回False
invisibility_of_element_located 判断某个元素中是否不存在于dom树或不可见
element_to_be_clickable 判断某个元素中是否可见并且是enable的, 这样的话才叫clickable
staleness_of 等某个元素从dom树中移除, 注意, 这个方法也是返回True或 False
element_to_be_selected 判断某个元素是否被选中了,一般用在下拉列表
element_selection_state_to_be 判断某个元素的选中状态是否符合预期
element_located_selection_state_to_be 跟上面的方法作用一样,只是上面的方法传入定位到的element, 而这个方法传入locator
alert_is_present 判断页面上是否存在alert

显示等待
结合WebDriverWait和expected_conditions判断元素是否存在,
每间隔1秒判断一次,10s超时,存在返回True,不存返回False

WebDriverWait类提供方法:
(1)until(method, message='')
  在规定时间内,每隔一段时间调用一下method方法,至到期返回值不为False,如果超时抛出带有message的TimeoutException异常信息

(1)until_not(method, message='')
  与until()方法相反,表示在规定时间内,每隔一段时间调用一下method方法,至到期返回值为False,如果超时抛出带有message的TimeoutException异常信息
:param locator: locator为元组类型,如("id", "kw")

定位搜索框,搜索电影;


url中 要调取的框子

from selenium import webdriver  
from selenium.webdriver import PhantomJS  # 使用无头浏览器
from selenium.webdriver.common.by import By   # 键盘操作
from selenium.webdriver.common.keys import Keys  # 负责操作界面;
from selenium.webdriver.support.ui import WebDriverWait  # 负责循环等待
from selenium.webdriver.support import expected_conditions as EC  # 负责条件触发;

import datetime, time, random

# #如果没有在环境变量指定PhantomJS位置
driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.set_window_size(1280,1080)

# 保存图片;
def savepic():
    basepath = 'F:/test/'
    filename = "{:%Y%m%d%H%M%S}-{:03}.png".format(datetime.datetime.now(), random.randint(1,100))
    driver.save_screenshot(basepath+filename)
    # 生成页面快照并保存

url = "https://movie.douban.com/"
driver.get(url)
# element = driver.find_element(By.ID, 'inp-qury')  # 找到搜索框 1;

# 在10s内, 定位元素inp-query , 元素加载到DOM,但是不保证他是可见的;
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located(  # 元素加载到DOM,但是不保证他是可见的;
            (By.ID, "inp-query")   # 找搜索框 是 元组
        )
    )
    element.send_keys('TRON')
    element.send_keys(Keys.ENTER)
    print(driver.current_url)
    savepic()

except Exception as e:
    print(type(e), e)
finally:
    driver.quit()
#----------------------------------------------------
C:\ProgramData\Miniconda3\envs\blog\lib\site-packages\selenium\webdriver\phantomjs\webdriver.py:49: UserWarning: Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead
  warnings.warn('Selenium support for PhantomJS has been deprecated, please use headless '
https://search.douban.com/movie/subject_search?search_text=TRON&cat=1002  #搜索网页;

隐式等待
找不到这个元素,继续等10s,还是找不到元素,结束程序;

from selenium import webdriver
from selenium.webdriver import PhantomJS  # 使用无头浏览器
from selenium.webdriver.common.by import By   # 键盘操作
from selenium.webdriver.common.keys import Keys  # 负责操作界面;
from selenium.webdriver.support.ui import WebDriverWait  # 负责循环等待
from selenium.webdriver.support import expected_conditions as EC  # 负责条件触发;

import datetime, time, random

# #如果没有在环境变量指定PhantomJS位置
driver = PhantomJS('F:/BaiduNetdiskDownload/2019 Python网络期班配套资料/slides/chapter16爬虫/install/phantomjs-2.1.1-windows/bin/phantomjs.exe')
driver.implicitly_wait(10) # 拿到driver等10s
driver.set_window_size(1280,1080)

# 保存图片;
def savepic():
    basepath = 'F:/test/'
    filename = "{:%Y%m%d%H%M%S}-{:03}.png".format(datetime.datetime.now(), random.randint(1,100))
    driver.save_screenshot(basepath+filename)
    # 生成页面快照并保存

url = "https://movie.douban.com/"
driver.get(url)


# 等 10s, 元素加载到DOM树,找id=inp-query
try:
    element = driver.find_element(By.ID, 'inp-query')  # 找到搜索框 1;
    # element = WebDriverWait(driver, 1).until(
    #     EC.presence_of_element_located(  # 元素加载到DOM,但是不保证他是可见的;
    #         (By.ID, "inp-query")   # 找搜索框 是 元组
    #     )
    # )
    element.send_keys('TRON')
    element.send_keys(Keys.ENTER)
    print(driver.current_url) # 新的url;
    savepic()

except Exception as e:
    print(type(e), e)
finally:
    driver.quit()
#----------------------------------
https://search.douban.com/movie/subject_search?search_text=TRON&cat=1002


<class 'selenium.common.exceptions.NoSuchElementException'> Message: {"errorMessage":"Unable to find element with id 'inp-qu1ery'","request":{"headers":{"Accept":"application/json","Accept-Encoding":"identity","Content-Length":"91","Content-Type":"application/json;charset=UTF-8","Host":"127.0.0.1:4483","User-Agent":"selenium/3.141.0 (python windows)"},"httpVersion":"1.1","method":"POST","post":"{\"using\": \"id\", \"value\": \"inp-qu1ery\", \"sessionId\": \"bb714600-ed9e-11ea-bb6d-6b286a00b9a6\"}","url":"/element","urlParsed":{"anchor":"","query":"","file":"element","directory":"/","path":"/element","relative":"/element","port":"","host":"","password":"","user":"","userInfo":"","authority":"","protocol":"","source":"/element","queryKey":{},"chunks":["element"]},"urlOriginal":"/session/bb714600-ed9e-11ea-bb6d-6b286a00b9a6/element"}}
Screenshot: available via screen
总结

Selenium的Web Driver是其核心, 从Selenium 2开始就是最重要的编程核心对象, 在Selenium 3中更是如此。

和浏览器交互全靠它,它可以:

  • 打开URL, 可以跟踪跳转, 可以返回当前页面的实际URL
  • 获取页面的title
  • 处理cookie
  • 控制浏览器的操作,例如前进、后退、刷新、关闭,最大化等
  • 执行JS脚本
  • 在DOM中搜索页面元素Web Element, 指定的或一批, find系方法
  • 操作网页元素
    • 模拟下拉框操作Select(element)
    • 在元素上模拟鼠标操作click()
    • 在元素上模拟键盘输入send_keys()
    • 获取元素文字text
    • 获取元素的属性get_attribute()

Selenium通过Web Driver来驱动浏览器工作, 而浏览器是一个个独立的浏览器进程。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343