PHP cURL庫函數抓取頁面內容

原文地址:PHPcURL庫函數抓取頁面內容(轉)作者:巴克

cURL是一個利用URL語法規定來傳輸文件和數據的工具,支持很多協議和選項,如HTTP、FTP、TELNET等,能提供URL 請求相關的各種細節信息。最爽的是,PHP 也支持cURL 庫

本文將介紹 cURL 的一些高級特性,以及在 PHP 中如何運用它。

1 為什么要用cURL?

是的,我們可以通過其他辦法獲取網頁內容。大多數時候,我因為想偷懶,都直接用簡單的 PHP的file_get_contents()函數:

$content = file_get_contents("http://www.awaimai.com");$lines = file("http://www.awaimai.com");readfile(http://www.awaimai.com);

不過,這種做法缺乏靈活性和有效的錯誤處理。而且,你也不能用它完成一些高難度任務,比如處理:coockies、驗證、表單提交、文件上傳等等。

2 啟用cURL

首先,我們得先要確定 PHP 是否開啟了這個庫,你可以通過使用phpinfo()函數來得到這一信息。如果在網頁上看到下面的輸出,那么表示 cURL 庫已開啟。

如果 curl沒有開啟,那么就需要開啟這個庫。如果是在Windows平臺下,那么非常簡單,你需要改一改php.ini文件的設置,找到php_curl.dll,并取消前面的分號注釋就行了。如下所示:

# 取消下面的注釋extension=php_curl.dll

如果是 Linux 服務器,需要重新編譯 PHP ,編譯時在configure命令上加上--with-curl參數。

3 基本結構

在學習更為復雜的功能之前,先來看一下在 PHP 中建立 cURL 請求的基本步驟:

初始化

設置選項

執行并獲取結果

釋放cURL句柄

實現代碼如下:

// 1. 初始化$ch = curl_init();// 2. 設置選項curl_setopt($ch, CURLOPT_URL,"http://www.awaimai.com");// 設置要抓取的頁面地址curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);// 抓取結果直接返回(如果為0,則直接輸出內容到頁面)curl_setopt($ch, CURLOPT_HEADER,0);// 不需要頁面的HTTP頭// 3. 執行并獲取HTML文檔內容,可用echo輸出內容$output = curl_exec($ch);// 4. 釋放curl句柄curl_close($ch);

第二步(也就是curl_setopt())最為重要,一切玄妙均在此。有一長串cURL參數可供設置,它們能指定 URL請求的各個細節。要一次性全部看完并理解可能比較困難,所以今天我們只試一下那些更常用也更有用的選項。

4 檢查錯誤

你可以在cur_exec()后加一段檢查錯誤的語句(雖然這并不是必需的):

$output = curl_exec($ch);if($output ===FALSE) {echo"cURL Error: ". curl_error($ch);}

請注意,比較的時候我們用的是=== FALSE,而非==FALSE。因為我們得區分空輸出和布爾值FALSE,后者才是真正的錯誤。

5 獲取信息

利用curl_getinfo()能夠在 cURL執行后獲取請求的有關信息,當然,這也是一個可選的設置項,:

curl_exec($ch);$info= curl_getinfo($ch);echo'獲取'.$info['url'] .'耗時'.$info['total_time'] .'秒';

返回的數組中包括了以下信息:

url//資源網絡地址

content_type//內容編碼

http_code//HTTP狀態碼

header_size//header的大小

request_size//請求的大小

filetime//文件創建時間

ssl_verify_result//SSL驗證結果

redirect_count//跳轉技術

total_time//總耗時

namelookup_time//DNS查詢耗時

connect_time//等待連接耗時

pretransfer_time//傳輸前準備耗時

size_upload//上傳數據的大小

size_download//下載數據的大小

speed_download//下載速度

speed_upload//上傳速度

download_content_length//下載內容的長度

upload_content_length//上傳內容的長度

starttransfer_time//開始傳輸的時間

redirect_time//重定向耗時

6 基于瀏覽器的重定向

在第一個例子中,我們將提供一段用于偵測服務器是否有基于瀏覽器的重定向的代碼。例如,有些網站會根據是否是手機瀏覽器甚至用戶來自哪個國家來重定向網頁。

我們利用CURLOPT_HTTPHEADER選項來設定發送出的HTTP請求頭信息(http headers),包括useragent信息和默認語言。然后看看這些特定網站是否會把我們重定向到不同的URL。

// 測試用的URL$urls =array("http://www.bbc.com","http://www.baidu.com","http://www.ubuntu.com");// 測試用的瀏覽器信息$browsers =array("standard"=>array("user_agent"=>"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)","language"=>"en-us,en;q=0.5"),"iphone"=>array("user_agent"=>"Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A537a Safari/419.3","language"=>"en"),"french"=>array("user_agent"=>"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; .NET CLR 2.0.50727)","language"=>"fr,fr-FR;q=0.5"));foreach($urlsas$url) {echo"URL: $urln

";foreach($browsersas$test_name => $browser) {? ? ? ? ? ? ? ? $ch = curl_init();// 設置 urlcurl_setopt($ch, CURLOPT_URL, $url);// 設置瀏覽器的特定headercurl_setopt($ch, CURLOPT_HTTPHEADER,array("User-Agent: {$browser['user_agent']}","Accept-Language: {$browser['language']}"));// 頁面內容我們并不需要curl_setopt($ch, CURLOPT_NOBODY,1);// 只需返回HTTP headercurl_setopt($ch, CURLOPT_HEADER,1);// 返回結果,而不是輸出它curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);? ? ? ? ? ? ? ? $output = curl_exec($ch);? ? ? ? ? ? ? ? curl_close($ch);// 有重定向的HTTP頭信息嗎?if(preg_match("!Location: (.*)!", $output, $matches)) {echo"$test_name: redirects to $matches[1]n

";? ? ? ? ? ? ? ? }else{echo"$test_name: no redirectionn

";? ? ? ? ? ? ? ? }? ? ? ? }echo"nn

";}

首先,我們建立一組需要測試的URL,接著指定一組需要測試的瀏覽器信息。最后通過循環測試各種URL和瀏覽器匹配可能產生的情況。

因為我們指定了CURLOPT_NOBODY選項,所以返回的輸出內容則只包括HTTP頭信息(被存放于$output中)。利用一個簡單的正則,我們檢查這個頭信息中是否包含了Location:字樣。

運行這段代碼應該會返回如下結果:

URL: http://www.bbc.comstandard: no redirectioniphone: no redirectionfrench: no redirectionURL: http://www.baidu.comstandard: redirects to https://www.baidu.com/iphone: no redirectionfrench: redirects to https://www.baidu.com/URL: http://www.ubuntu.comstandard: redirects to http://www.ubuntu.com/index_kyliniphone: redirects to http://www.ubuntu.com/index_kylinfrench: redirects to http://www.ubuntu.com/index_kylin

7

用POST方法發送數據

當發起 GET 請求時,數據可以通過“查詢字串”(Query String)傳遞給一個URL。例如,在必應(鑒于

Google 需要翻墻,用 Bing 代替)中搜索時,搜索關鍵即為 URL 的查詢字串的一部分:

http://www.bing.com?q=awaimai.com

這種情況下你可能并不需要 cURL 來模擬。把這個URL丟給file_get_contents()就能得到相同結果。

不過有一些HTML表單是用 POST 方法提交的。這種表單提交時,數據是通過 HTTP請求體(requestbody) 發送,而不是查詢字串。例如,當使用ThinkPHP網站的搜索功能時,無論輸入什么關鍵字,總是被 POST到如下頁面:

http://www.thinkphp.cn/Search/

你可以用 PHP 腳本來模擬這種 URL 請求。首先,新建一個可以接受并顯示 POST數據的文件,我們給它命名為post_output.php,腳本內容為:

print_r($_POST);

接下來,寫一段 PHP 腳本來執行 cURL 請求:

$url ="http://localhost/post_output.php";$post_data =array("foo"=>"bar","query"=>"Nettuts","action"=>"Submit");$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);// 我們在POST數據哦!curl_setopt($ch, CURLOPT_POST,1);// 加上POST變量curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);$output = curl_exec($ch);curl_close($ch);echo$output;

執行代碼后應該會得到以下結果:

Array(? ? [foo] => bar? ? [query] => Nettuts? ? [action] => Submit)

這段腳本發送一個 POST 請求給post_output.php,這個頁面$_POST變量并返回,我們利用cURL 捕捉了這個輸出。

8 文件上傳

上傳文件和前面的 POST十分相似。因為所有的文件上傳表單都是通過POST方法提交的。首先新建一個接收文件的頁面,命名為upload_output.php,頁面內容:

print_r($_FILES);

以下是真正執行文件上傳任務的腳本,命名為upload.php,內容:

$url ="http://localhost/upload_output.php";$post_data =array("foo"=>"bar",// 要上傳的本地文件地址"upload"=>"@C:/wamp/www/test.zip");$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);curl_setopt($ch, CURLOPT_POST,1);curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);$output = curl_exec($ch);curl_close($ch);echo$output;

如果你需要上傳一個文件,只需要把文件路徑賦給upload,作為POST變量傳過去,不過記得在前面加上@符號。執行這段腳本應該會得到類似如下輸出:

Array(? ? [upload] =>Array([name] => test.zip[type] => application/octet-stream[tmp_name] => C:Windowsphp1BB4.tmp[error] =>0[size] =>487235))

9 cURL批處理(multi

cURL)

cURL還有一個高級特性:批處理句柄(handle)。這一特性允許你同時或異步地打開多個URL連接。下面是來自來自php.net的示例代碼

// 創建兩個cURL資源$ch1 = curl_init();$ch2 = curl_init();// 指定URL和適當的參數curl_setopt($ch1, CURLOPT_URL,"http://lxr.php.net/");curl_setopt($ch1, CURLOPT_HEADER,0);curl_setopt($ch2, CURLOPT_URL,"http://www.php.net/");curl_setopt($ch2, CURLOPT_HEADER,0);// 創建cURL批處理句柄$mh = curl_multi_init();// 加上前面兩個資源句柄curl_multi_add_handle($mh, $ch1);curl_multi_add_handle($mh, $ch2);// 預定義一個狀態變量$active =null;// 執行批處理do{? ? $mrc = curl_multi_exec($mh, $active);}while($mrc == CURLM_CALL_MULTI_PERFORM);while($active && $mrc == CURLM_OK) {if(curl_multi_select($mh) !=-1) {do{? ? ? ? ? ? $mrc = curl_multi_exec($mh, $active);? ? ? ? }while($mrc == CURLM_CALL_MULTI_PERFORM);? ? }}// 關閉各個句柄curl_multi_remove_handle($mh, $ch1);curl_multi_remove_handle($mh, $ch2);curl_multi_close($mh);

這里要做的就是打開多個 cURL 句柄并指派給一個批處理句柄。然后你就只需在一個while循環里等它執行完畢。

這個示例中有兩個主要循環。第一個do-while循環重復調用curl_multi_exec()。這個函數是無隔斷(non-blocking)的,但會盡可能少地執行。它返回一個狀態值,只要這個值等于常量CURLM_CALL_MULTI_PERFORM,就代表還有一些刻不容緩的工作要做(例如,把對應URL的http頭信息發送出去)。也就是說,我們需要不斷調用該函數,直到返回值發生改變。

而接下來的while循環,只在$active變量為true時繼續。這一變量之前作為第二個參數傳給了curl_multi_exec(),代表只要批處理句柄中是否還有活動連接。接著,我們調用curl_multi_select(),在活動連接(例如接受服務器響應)出現之前,它都是被“屏蔽”的。這個函數成功執行后,我們又會進入另一個do-while循環,繼續下一條URL。

還是來看一看怎么把這一功能用到實處吧:

9.1 WordPress 鏈接檢查器

想象一下你有一個文章數目龐大的博客,這些文章中包含了大量外部網站鏈接。一段時間之后,因為這樣那樣的原因,這些鏈接中相當數量都失效了。要么是被和諧了,要么是整個站點都被功夫網了…

我們下面建立一個腳本,分析所有這些鏈接,找出打不開或者404的網站/網頁,并生成一個報告。

請注意,以下并不是一個真正可用的WordPress插件,僅僅是一段獨立功能的腳本而已,僅供演示,謝謝。

好,開始吧。首先,從數據庫中讀取所有這些鏈接:

// 配置 MySQL 數據庫$db_host ='localhost';$db_user ='root';$db_pass ='';$db_name ='wordpress';$excluded_domains =array('localhost','www.mydomain.com');$max_connections =10;// 初始化一些變量$url_list =array();$working_urls =array();$dead_urls =array();$not_found_urls =array();$active =null;// 連到 MySQLif(!mysql_connect($db_host, $db_user, $db_pass)) {die('Could not connect: '. mysql_error());}if(!mysql_select_db($db_name)) {die('Could not select db: '. mysql_error());}// 找出所有含有鏈接的文章$sql ="SELECT post_content FROM wp_posts

WHERE post_content LIKE '%href=%'

AND post_status = 'publish'

AND post_type = 'post'";$res = mysql_query($sql)ordie(mysql_error());while($d = mysql_fetch_assoc($res)) {// 用正則匹配鏈接if(preg_match_all("!href="(.*?)"!", $d['post_content'], $matches)) {foreach($matches[1]as$url) {// 剔除排除的域名$tmp = parse_url($url);if(in_array($tmp['host'], $excluded_domains)) {continue;? ? ? ? ? ? ? ? ? ? ? ? }// 保存 URL$url_list []= $url;? ? ? ? ? ? ? ? }? ? ? ? }}// 移除重復鏈接$url_list = array_values(array_unique($url_list));if(!$url_list) {die('No URL to check');}

我們首先配置好數據庫,一系列要排除的域名($excluded_domains),以及最大同時連接數量($max_connections)。然后,連接數據庫,獲取文章和包含的鏈接,把它們收集到一個數組中($url_list)。

下面的代碼有點復雜了,因此我將一小步一小步地詳細解釋:

// 1. 批處理器$mh = curl_multi_init();// 2. 加入需批量處理的URLfor($i =0; $i < $max_connections; $i++) {? ? ? ? add_url_to_multi_handle($mh, $url_list);}// 3. 初始處理do{? ? ? ? $mrc = curl_multi_exec($mh, $active);}while($mrc == CURLM_CALL_MULTI_PERFORM);// 4. 主循環while($active && $mrc == CURLM_OK) {// 5. 有活動連接if(curl_multi_select($mh) !=-1) {// 6. 干活do{? ? ? ? ? ? ? ? ? ? ? ? $mrc = curl_multi_exec($mh, $active);? ? ? ? ? ? ? ? }while($mrc == CURLM_CALL_MULTI_PERFORM);// 7. 有信息否?if($mhinfo = curl_multi_info_read($mh)) {// 意味著該連接正常結束// 8. 從curl句柄獲取信息$chinfo = curl_getinfo($mhinfo['handle']);// 9. 死鏈么?if(!$chinfo['http_code']) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $dead_urls []= $chinfo['url'];// 10. 404了?}elseif($chinfo['http_code'] ==404) {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $not_found_urls []= $chinfo['url'];// 11. 還能用}else{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $working_urls []= $chinfo['url'];? ? ? ? ? ? ? ? ? ? ? ? }// 12. 移除句柄curl_multi_remove_handle($mh, $mhinfo['handle']);? ? ? ? ? ? ? ? ? ? ? ? curl_close($mhinfo['handle']);// 13. 加入新URL,干活if(add_url_to_multi_handle($mh, $url_list)) {do{? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? $mrc = curl_multi_exec($mh, $active);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }while($mrc == CURLM_CALL_MULTI_PERFORM);? ? ? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? }}// 14. 完了curl_multi_close($mh);echo"==Dead URLs==n";echoimplode("n",$dead_urls) ."nn";echo"==404 URLs==n";echoimplode("n",$not_found_urls) ."nn";echo"==Working URLs==n";echoimplode("n",$working_urls);// 15. 向批處理器添加urlfunctionadd_url_to_multi_handle($mh, $url_list){static$index =0;// 如果還剩url沒用if($url_list[$index]) {// 新建curl句柄$ch = curl_init();// 配置urlcurl_setopt($ch, CURLOPT_URL, $url_list[$index]);// 不想輸出返回的內容curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);// 重定向到哪兒我們就去哪兒curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);// 不需要內容體,能夠節約帶寬和時間curl_setopt($ch, CURLOPT_NOBODY,1);// 加入到批處理器中curl_multi_add_handle($mh, $ch);// 撥一下計數器,下次調用該函數就能添加下一個url了$index++;returntrue;? ? ? ? }else{// 沒有新的URL需要處理了returnfalse;? ? ? ? }}

下面解釋一下以上代碼。列表的序號對應著代碼注釋中的順序數字。

新建一個批處理句柄。

稍后我們將創建一個把URL加入批處理器的函數add_url_to_multi_handle()。每當這個函數被調用,就有一個新url被加入批處理器。一開始,我們給批處理器添加了10個URL(這一數字由$max_connections所決定)。

運行curl_multi_exec()進行初始化工作是必須的,只要它返回CURLM_CALL_MULTI_PERFORM就還有事情要做。這么做主要是為了創建連接,它不會等待完整的URL響應。

只要批處理中還有活動連接主循環就會一直持續。

curl_multi_select()會一直等待,直到某個URL查詢產生活動連接。

cURL的活兒又來了,主要是獲取響應數據。

檢查各種信息。當一個URL請求完成時,會返回一個數組。

在返回的數組中有一個 cURL 句柄。我們利用其獲取單個 cURL 請求的相應信息。

如果這是一個死鏈或者請求超時,不會返回http狀態碼。

如果這個頁面找不到了,會返回404狀態碼。

其他情況我們都認為這個鏈接是可用的(當然,你也可以再檢查一下500錯誤之類…)。

從該批次移除這個 cURL 句柄,因為它已經沒有利用價值了,關了它!

很好,現在可以另外加一個URL進來了。再一次地,初始化工作又開始進行…

嗯,該干的都干了。關閉批處理器,生成報告。

回過頭來看給批處理器添加新 URL 的函數。這個函數每調用一次,靜態變量$index就遞增一次,這樣我們才能知道還剩多少URL 沒處理。

我把這個腳本在我的博客上跑了一遍(測試需要,有一些錯誤鏈接是故意加上的),共檢查約40個URL,只耗費兩秒不到。當需要檢查更加大量的URL時,其省心省力的效果可想而知!如果你同時打開10個連接,還能再快上10倍!另外,你還可以利用cURL批處理的無隔斷特性,來處理大量URL請求,而不會阻塞你的Web腳本。

10 另一些有用的cURL

選項

10.1 HTTP 認證

如果某個URL請求需要基于 HTTP 的身份驗證,你可以使用下面的代碼:

$url ="http://www.somesite.com/members/";$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);// 發送用戶名和密碼curl_setopt($ch, CURLOPT_USERPWD,"myusername:mypassword");// 你可以允許其重定向curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);// 下面的選項讓 cURL 在重定向后// 也能發送用戶名和密碼curl_setopt($ch, CURLOPT_UNRESTRICTED_AUTH,1);$output = curl_exec($ch);curl_close($ch);

10.2 FTP 上傳

PHP 自帶有FTP 類庫, 但你也能用 cURL:

// 打開一個文件指針$file = fopen("/path/to/file","r");$size = filesize("/path/to/file");// url里包含了大部分所需信息$url ="ftp://username:password@mydomain.com:21/path/to/new/file";$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);// 上傳相關的選項curl_setopt($ch, CURLOPT_UPLOAD,1);curl_setopt($ch, CURLOPT_INFILE, $file);curl_setopt($ch, CURLOPT_INFILESIZE, $size);// 是否開啟ASCII模式 (上傳文本文件時有用)curl_setopt($ch, CURLOPT_FTPASCII,1);$output = curl_exec($ch);curl_close($ch);

10.3 代理/翻墻請求

你可以用代理發起 cURL 請求:

$ch = curl_init();curl_setopt($ch, CURLOPT_URL,'http://www.example.com');curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);// 指定代理地址curl_setopt($ch, CURLOPT_PROXY,'11.11.11.11:8080');// 如果需要的話,提供用戶名和密碼curl_setopt($ch, CURLOPT_PROXYUSERPWD,'username:password');$output = curl_exec($ch);curl_close ($ch);

10.4 回調函數

可以在一個URL請求過程中,讓 cURL

調用某指定的回調函數。例如,在內容或者響應下載的過程中,立刻開始利用數據,而不用等到完全下載完。

$ch = curl_init();curl_setopt($ch, CURLOPT_URL,'http://net.tutsplus.com');curl_setopt($ch, CURLOPT_WRITEFUNCTION,"progress_function");curl_exec($ch);curl_close ($ch);functionprogress_function($ch, $str){echo$str;returnstrlen($str);}

這個回調函數必須返回字串的長度,不然此功能將無法正常使用。在URL響應接收的過程中,只要收到一個數據包,這個函數就會被調用。

更多信息請關注千鋒PHP,千鋒論壇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容