﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Xiaoxia[PG]</title>
	<atom:link href="http://xiaoxia.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://xiaoxia.org</link>
	<description>Yesterday is history, tomorrow is mistery, today is a gift!</description>
	<lastBuildDate>Tue, 15 May 2012 18:44:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>MySQL数据库优化的一些笔记</title>
		<link>http://xiaoxia.org/2012/05/16/mysql-optimize/</link>
		<comments>http://xiaoxia.org/2012/05/16/mysql-optimize/#comments</comments>
		<pubDate>Tue, 15 May 2012 18:38:58 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Internet]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4971</guid>
		<description><![CDATA[0. 索引很重要 之前列举记录用了下面的语句。state字段为索引。 SELECT * FROM feed_urls WHERE state='ok' AND feed_url&#60;&#62;'' LIMIT N,10 当记录数量很大时，有几万之后，这句SQL就很慢了。主要是因为feed_url没有建立索引。后来的解决方法是，把feed_url为空的，设为一个ok以外的state值，就行了。 1、索引不是万能的 为了计算记录总数，下面的语句会很慢。 mysql&#62; SELECT COUNT(*) FROM feed_urls WHERE state='error'; +----------+ &#124; COUNT(*) &#124; +----------+ &#124; 30715 &#124; +----------+ 1 row in set (0.14 sec) mysql&#62; EXPLAIN SELECT COUNT(*) FROM feed_urls WHERE state='error'\G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: [...]]]></description>
			<content:encoded><![CDATA[<p><strong>0. 索引很重要</strong></p>
<p>之前列举记录用了下面的语句。state字段为索引。</p>
<blockquote>
<pre>
SELECT * FROM feed_urls WHERE state='ok' AND feed_url&lt;&gt;'' LIMIT N,10
</pre>
</blockquote>
<p>当记录数量很大时，有几万之后，这句SQL就很慢了。主要是因为feed_url没有建立索引。后来的解决方法是，把feed_url为空的，设为一个ok以外的state值，就行了。</p>
<p><strong>1、索引不是万能的</strong></p>
<p>为了计算记录总数，下面的语句会很慢。<br />
<span id="more-4971"></span></p>
<blockquote>
<pre>
mysql&gt; SELECT COUNT(*) FROM feed_urls WHERE state='error';
+----------+
| COUNT(*) |
+----------+
|    30715 |
+----------+
1 row in set (0.14 sec)

mysql&gt; EXPLAIN SELECT COUNT(*) FROM feed_urls WHERE state='error'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: ref
possible_keys: state,page_index
          key: page_index
      key_len: 10
          ref: const
         rows: 25936
        Extra: Using where; Using index
1 row in set (0.00 sec)
</pre>
</blockquote>
<p>state为索引，请求用时140ms。遍历了state='error'索引下的每一条记录。</p>
<blockquote>
<pre>
mysql&gt; SELECT state,COUNT(*) FROM feed_urls GROUP BY state;
+----------+----------+
| state    | COUNT(*) |
+----------+----------+
| error    |    30717 |
| fetching |        8 |
| nofeed   |    76461 |
| ok       |    74703 |
| queued   |   249681 |
+----------+----------+
5 rows in set (0.55 sec)

mysql&gt; EXPLAIN SELECT state,COUNT(*) FROM feed_urls GROUP BY state\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: index
possible_keys: NULL
          key: state
      key_len: 10
          ref: NULL
         rows: 431618
        Extra: Using index
1 row in set (0.00 sec)
</pre>
</blockquote>
<p>请求用时550ms。遍历了每个state下的每一条记录。</p>
<p><strong>改进方法：</strong></p>
<p>独立一个表用来计数，使用MySQL的Trigger同步计数：</p>
<blockquote>
<pre>
CREATE TRIGGER my_trigger AFTER UPDATE ON feed_urls
FOR EACH ROW BEGIN

IF OLD.state &lt;&gt; NEW.state THEN

IF NEW.state='ok' THEN
    UPDATE feed_stat SET count_feed = count_feed + 1;
END IF;

IF NEW.state IN ('ok', 'error', 'nofeed') THEN
    UPDATE feed_stat SET count_access = count_access + 1;
END IF;

END IF;

END
</pre>
</blockquote>
<p><strong>2. 当分页很大时</strong></p>
<blockquote>
<pre>
mysql&gt; SELECT * FROM feed_urls LIMIT 230000, 1\G
*************************** 1. row ***************************
         id: 736841f82abb0bc87ccfec7c0fdbd09c30b5a24d
       link: http://mappemunde.typepad.com/
      title: Tim Peterson
   feed_url: NULL
update_time: 2012-05-12 11:01:56
      state: queued
http_server: NULL
   abstract: NULL
previous_id: ceea30e0ba609b69198c53ce71c44070d69038c5
  ref_count: 1
      error: NULL
        aid: 230001
1 row in set (0.50 sec)

mysql&gt; EXPLAIN SELECT * FROM feed_urls LIMIT 230000, 1\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: feed_urls
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 431751
        Extra:
1 row in set (0.00 sec)
</pre>
</blockquote>
<p>读取一条记录，耗时500ms，因为表记录是变长的，所以MySQL不能算出目标位置，只能每一条记录的数过去。</p>
<p><strong>改进方法：</strong></p>
<p>通过索引定位，数索引比数记录要快，因为索引占用的空间比整条记录小很多。</p>
<blockquote>
<pre>
mysql&gt; SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid\G
*************************** 1. row ***************************
        aid: 215001
         id: 2e4b1a385c8aae40b3ec2af9153805ca446f2029
       link: http://ncse.com/
      title: NCSE
   feed_url: NULL
update_time: 2012-05-12 10:47:15
      state: queued
http_server: NULL
   abstract: NULL
previous_id: 819a6e3c5edc1624a9b8f171d8d3ae269843785f
  ref_count: 3
      error: NULL
        aid: 215001
1 row in set (0.06 sec)

mysql> EXPLAIN SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: <derived2>
         type: system
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
        Extra:
*************************** 2. row ***************************
           id: 1
  select_type: PRIMARY
        table: u
         type: const
possible_keys: aid
          key: aid
      key_len: 4
          ref: const
         rows: 1
        Extra:
*************************** 3. row ***************************
           id: 2
  select_type: DERIVED
        table: feed_urls
         type: index
possible_keys: NULL
          key: aid
      key_len: 4
          ref: NULL
         rows: 211001
        Extra: Using index
3 rows in set (0.15 sec)
</pre>
</blockquote>
<p>耗时60ms，比之前的方法快了将近10倍。如果LIMIT语句里还有WHERE a=1，应该建立一个（a，aid）的索引。</p>
<p>话说，MySQL好像还是不能直接算出第21500条索引的位置呀，这种方法还是数了索引了，能算出来就直接0ms了。不过这样的效率，对于百万级的，还能应付吧。如果是千万级的或者像我之前在KS创建的一张上亿条记录的表（120G），这种方法就肯定不行了。</p>
<p>经过上述优化，打开最后一页的速度已经很快了（之前需要800ms，现在则为300ms左右）。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed10.png"><img src="http://xiaoxia.org/upfiles/2012/05/feed10.png" alt="" title="feed10" width="648" height="77" class="alignnone size-full wp-image-4972" /></a></p>
<p>膜拜下这Burst.NET最低档次的VPS (30RMB/month)。</p>
<blockquote>
<pre>root@xiaoxia-pc:~/# ping feed.readself.com -n
PING app.readself.com (184.82.185.32) 56(84) bytes of data.
64 bytes from 184.82.185.32: icmp_req=1 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=2 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=3 ttl=45 time=161 ms
</pre>
</blockquote>
<p>用同样的方法，优化了搜索引擎的排名算法。即排名过程中选取尽量少的值出来排序，排序后再JOIN一次获取结果的信息。</p>
<p>排序过程如下：</p>
<blockquote>
<pre>
SELECT u.*, count_level(u.id) lv
  FROM(
    SELECT f.id, f.ref_count, MATCH(i.link,i.title) AGAINST (keywords) score
    FROM feed_index i
    JOIN feed_urls f ON f.id=i.id
    WHERE MATCH(i.link,i.title) AGAINST (keywords)
    ORDER BY score*0.5 + score*0.5*(ref_count/max_ref_count_in_result) DESC
  LIMIT offset,10
) d JOIN feed_urls u ON u.id = d.id
</pre>
</blockquote>
<p>目前处理10万记录的全文索引数据，MySQL还是可以满足的，就是不知道上百万之后，还能不能撑下去。撑不下去就依赖第三方的工具了，例如Sphinx <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>3. SELECT里的函数</strong></p>
<p>给FeedDB增加了层次的显示。因为本人太懒，所以没有给数据库表增加一个记录深度的字段。所以，直接写了一个MySQL的自定义函数 count_level，用来统计通过parent_id一直找到顶层经过的路径长度（Level）。</p>
<blockquote>
<pre>
CREATE DEFINER=`feeddb_rw`@`%` FUNCTION `count_level`(fid char(40)) RETURNS int(11)
BEGIN
     SET @levels = 0;
     SET @found = false;
     WHILE NOT @found DO
	     SELECT previous_id INTO @prev_id FROM feed_urls WHERE id=fid;
	     IF @prev_id is null OR @prev_id = '' THEN
		SET @found = true;
             ELSE
             	SET @levels = @levels + 1;
             	SET fid = @prev_id;
	     END IF;
     END WHILE;
     IF @prev_id is null THEN
         RETURN null;
     END IF;
     RETURN  @levels;
END
</pre>
</blockquote>
<p>在网页显示的时候用了类似下面的SQL语句。</p>
<blockquote>
<pre>
mysql&gt; SELECT u.*, count_level(u.id) FROM feed_urls u ORDER BY ref_count DESC LIMIT 12000,1\G
*************************** 1. row ***************************
               id: e42f44b04dabbb9789ccb4709278e881c54c28a3
             link: http://tetellita.blogspot.com/
            title: le hamburger et le croissant
         feed_url: http://www.blogger.com/feeds/7360650/posts/default
      update_time: 2012-05-15 14:50:53
            state: ok
      http_server: GSE
         abstract: Lepekmezest un épais sirop bordeaux obtenu par réduction dumoût de raisin,&nbsp;une sorte de mélasse de raisin, en somme. Légèrement acidulé, il apporte du pep's aux yaourts et nappe avec bonheur les
      previous_id: 129cabd96e7099a53b78c7ddeff98658351082e9
        ref_count: 9
            error: NULL
              aid: 174262
count_level(u.id): 8
1 row in set (4.10 sec)
</pre>
</blockquote>
<p>好吧，悲剧了！4100ms。一定对12000个条目都算了一次count_level，然后再进行排序。所以才用上了4秒那么漫长的时间！！！</p>
<p><strong>改进方法：</strong></p>
<p>先SELECT LIMIT，再在派生的临时表里，计算count_level。</p>
<blockquote>
<pre>
mysql&gt; SELECT u.*, count_level(u.id) FROM (
      SELECT id FROM feed_urls ORDER BY ref_count DESC LIMIT 27521,1
 ) d JOIN feed_urls u ON u.id=d.id\G
*************************** 1. row ***************************
               id: 61df288dda131ffd6125452d20ad0648f38abafd
             link: http://mynokiamobile.org/
            title: My Nokia Mobile
         feed_url: http://mynokiamobile.org/feed/
      update_time: 2012-05-14 14:06:57
            state: ok
      http_server: Apache/2.2.19 (Unix) mod_ssl/2.2.19 OpenSSL/1.0.0-fips mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
         abstract: ArchivesSelect MonthMay 2012April 2012March 2012February 2012January 2012December 2011November 2011October 2011September 2011August 2011July 2011June 2011May 2011April 2011March 2011February 2011Janua
      previous_id: f37af92bb89c08f6d4b69e72eab05d8ab1e2aca4
        ref_count: 5
            error: NULL
              aid: 154996
count_level(u.id): 8
1 row in set (0.09 sec)
</pre>
</blockquote>
<p>如此，优化之后效果好很多了！但是还可以继续优化，例如建立一个字段存储Level的值应该是最好的办法了。</p>
<p>初次了解MySQL一些工作机制，欢迎一起探讨！</p>
<p>参考文献：</p>
<p><a href="http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/">http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/</a><br />
<a href="http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/">http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/05/16/mysql-optimize/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>用MySQL全文索引给FeedDB打造一个搜索引擎</title>
		<link>http://xiaoxia.org/2012/05/13/mysql-fulltext-search-engine/</link>
		<comments>http://xiaoxia.org/2012/05/13/mysql-fulltext-search-engine/#comments</comments>
		<pubDate>Sat, 12 May 2012 19:45:27 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Internet]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4956</guid>
		<description><![CDATA[效果图，欢迎测试 http://feed.readself.com/ samhjn  同学在上一篇文章评论中表示 Feed Database 的搜索功能不好使。原因是之前我没有太注重搜索上的优化，所以这个功能的体验很差。例如输入 “xiaoxia” 结果搜出一大堆 “xiaoxiao” 的网站，排名还比我的博客靠前，挺失望的！不过，今天的工作就是把这个功能给完善了！现在已经不是之前那个单纯在MySQL里使用like '%keyword%'查找那么简陋了。而且搜索速度也大大提升，不再像之前那样慢。 只要你输入关键字“xiaoxia”进行搜索，绝对不会出现“xiaoxiao”的结果了，因为这是两个不同的名字。 &#160; 同时，你输入的关键词还会被拆分，例如“吸血鬼小说”会被拆分成“吸血鬼”和“小说”。排序方式为先按匹配词数，再按BR值（被友情链接数量）排序。 &#160; 提到搜索引擎技术就离不开分词和索引，在分词上，我使用的是 mmseg 的中文分算法和搜狗的词库，分词速度快的惊人。以至于我处理数据的瓶颈在MySQL数据库上。我使用了MySQL的fulltext索引功能，在检索效率上可能没有sphinx那么快，但是对于10万个条目以内的数据库，速度已经足够了。为了达到精确查找的目的，我只对网站链接和标题两个属性进行了索引，fulltext的索引数据占用的空间也不多，才不到10M，挺环保的。 对网站标题进行分词之后，连同需要建立索引的链接，一起搬到了一个叫feed_index的索引表中。 下面是未分词的一段数据： 分词之后的数据： 目前这个分词效果还是挺满意的。另外，在最近看的一本搜索引擎相关的书籍中，提到了一种不依赖于词库的分词方法，能够应付一些新生的词汇，有空研究一下。如果两种方法都结合起来，应该能够达到更好的效果 夜已深，明天继续研究！]]></description>
			<content:encoded><![CDATA[<p>效果图，欢迎测试 <a href="http://feed.readself.com/" target="_blank">http://feed.readself.com/</a></p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed9.png"><img class="alignnone size-full wp-image-4962" title="feed9" src="http://xiaoxia.org/upfiles/2012/05/feed9.png" alt="" width="477" height="426" /></a></p>
<p><span id="more-4956"></span></p>
<p><strong><a href="http://www.samhjn.co.cc/" rel="external nofollow">samhjn</a> </strong> 同学在上一篇文章评论中表示 <a href="http://feed.readself.com/" target="_blank">Feed Database</a> 的搜索功能不好使。原因是之前我没有太注重搜索上的优化，所以这个功能的体验很差。例如输入 “xiaoxia” 结果搜出一大堆 “xiaoxiao” 的网站，排名还比我的博客靠前，挺失望的！不过，今天的工作就是把这个功能给完善了！现在已经不是之前那个单纯在MySQL里使用like '%keyword%'查找那么简陋了。而且搜索速度也大大提升，不再像之前那样慢。</p>
<p>只要你输入关键字“xiaoxia”进行搜索，绝对不会出现“xiaoxiao”的结果了，因为这是两个不同的名字。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed4.png"><img class="alignnone size-medium wp-image-4957" title="feed4" src="http://xiaoxia.org/upfiles/2012/05/feed4-700x498.png" alt="" width="700" height="498" /></a></p>
<p>&nbsp;</p>
<p>同时，你输入的关键词还会被拆分，例如“吸血鬼小说”会被拆分成“吸血鬼”和“小说”。排序方式为先按匹配词数，再按BR值（被友情链接数量）排序。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed5.png"><img class="alignnone size-full wp-image-4958" title="feed5" src="http://xiaoxia.org/upfiles/2012/05/feed5.png" alt="" width="687" height="675" /></a></p>
<p>&nbsp;</p>
<p>提到搜索引擎技术就离不开分词和索引，在分词上，我使用的是 <a href="http://www.google.com.tw/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0CHUQFjAA&amp;url=http%3A%2F%2Ftechnology.chtsai.org%2Fmmseg%2F&amp;ei=PLiuT6LhA8mViAe6o5DgCA&amp;usg=AFQjCNGbckek52qT40k-56qFWrQF-jpD-g" target="_blank">mmseg</a> 的中文分算法和搜狗的词库，分词速度快的惊人。以至于我处理数据的瓶颈在MySQL数据库上。我使用了MySQL的fulltext索引功能，在检索效率上可能没有sphinx那么快，但是对于10万个条目以内的数据库，速度已经足够了。为了达到精确查找的目的，我只对网站链接和标题两个属性进行了索引，fulltext的索引数据占用的空间也不多，才不到10M，挺环保的。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed6.png"><img class="alignnone size-full wp-image-4959" title="feed6" src="http://xiaoxia.org/upfiles/2012/05/feed6.png" alt="" width="564" height="119" /></a></p>
<p>对网站标题进行分词之后，连同需要建立索引的链接，一起搬到了一个叫feed_index的索引表中。</p>
<p>下面是未分词的一段数据：</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed8.png"><img class="alignnone size-full wp-image-4961" title="feed8" src="http://xiaoxia.org/upfiles/2012/05/feed8.png" alt="" width="571" height="480" /></a></p>
<p>分词之后的数据：</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed7.png"><img class="alignnone size-full wp-image-4960" title="feed7" src="http://xiaoxia.org/upfiles/2012/05/feed7.png" alt="" width="556" height="480" /></a></p>
<p>目前这个分词效果还是挺满意的。另外，在最近看的一本搜索引擎相关的书籍中，提到了一种不依赖于词库的分词方法，能够应付一些新生的词汇，有空研究一下。如果两种方法都结合起来，应该能够达到更好的效果 <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>夜已深，明天继续研究！</p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/05/13/mysql-fulltext-search-engine/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>通过友情链接进行博客Feed的搜集，你的博客收录了吗</title>
		<link>http://xiaoxia.org/2012/05/12/blog-feed-crawler-python/</link>
		<comments>http://xiaoxia.org/2012/05/12/blog-feed-crawler-python/#comments</comments>
		<pubDate>Fri, 11 May 2012 19:16:14 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[我的代码]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4945</guid>
		<description><![CDATA[很久没有发一些有技术含量的文章了，最近发博文都有一种应付式的感觉，真对不起自己。感觉有时候是我沉醉于一样东西太长时间了，把我正常的生活节奏都打乱了，而却没有注意到这样子反而效率很低下。适时抽时间出来总结一下是蛮重要的！所以，以后决定每天都抽一个小时出来自我总结，觉得有所感想就写下来，有技术研究的，就给大家分享一下吧！ 这两天在写下面的一个东西，用来搜集博客种子（Feed）的RSS或者Atom地址的。没有种子的博客不会被收录进来。因为只有Feed才对我有用！ 网站地址：http://feed.readself.com/ 我的需求 因为我最近在做一个读书网站，需要从互联网博客频道中获取文章。之前通过人工添加了将近200个博客的Feed地址，定期更新以获取文章。如今阅读的基本功能已经完成，现在亟需的是大量的文章以供各种实验性的测试，例如文章分类，全文索引等，属于数据挖掘和模式匹配的范畴。 之前已经在构思用何种方式搜集互联网上的Feed来源，李劼杰同学的“中国个人博客索引”给了我很大的灵感。采用博客的“友情链接”的方式进行扩散搜索，而我仿效其方法采用BFS搜集博客的Feed。虽然我们俩做的是不同的方向，但是没想到这么巧合，他所分享的技术东西正是我所要研究的。 话说回来，我要采集的是博客的Feed地址，如何找呢？ 寻找Feed地址 最近研究得出的方法是，从博客页面（可以是首页或者是文章页面）的HTML中，遍历所有link标签，采集如下的href属性。 &#60;link rel="alternate" type="application/rss+xml" title="Xiaoxia[PG] &#38;raquo; Feed" href="http://xiaoxia.org/feed/" /&#62; 大部分博客的Feed都是按照上面的代码提供，RSS是其中一种聚合类型，还有另外一种常见的是Atom。而常见的RSS还有两种不同的版本，当然这个不需要关心，因为我现在使用FeedParser来帮我采集RSS或者Atom里的内容（这个开源的FeedPaser在处理不正确的RSS时经常出错，需要自己修正代码）。 另外需要注意的是，有点link标签并没有 ref="alternate" 这个属性，同时还有可能把评论的Feed或者RPC的XML收录进来了。这个时候就需要加以区别了。 我目前采用一种评分的方法，即完全匹配标准格式的，打10分满分。遇到下列情况，则会被扣分： 1、没有 ref="alternate" 这个属性。 2、href中含有comment字符。 3、href中含有rpc字符。 4、href中含有rsd字符。 在对所有含有RSS或者Atom的link进行评分后，选取最高分作为Feed的地址。 另外需要注意的问题是，href不一定是完整的URL地址，有可能是相对路径，所以需要对其补全。 寻找友情链接 既然过友情链接进行扩散搜集，就需要对每个博客的友情链接李劼杰同学采用的是固定的模板匹配的方法，这种方法的限制是只能识别支持的博客的友情链接，而面对未知的博客类型，就无法提取友情链接了。所以会影响总体搜集的友情链接的数量。而我采用的方法是，基于概率统计的方式，定位友情链接的容器标签。 首先，枚举所有可以存放友情链接的容器，我取了div、table、ul这三个，当然还可能有其他的我还没有考虑到，但这三个已经涵盖了大部分的博客的情况。 对枚举的每个容器，统计所有的链接（a标签）。判断是否为站外链接，如果是，则增加链接数量，以及增加链接文字数量（为何要这个？因为图片超链接将会被排除），否则增加站内链接数。如果该站外链接为新窗口打开，则有相应的奖励，我目前是多算一次链接数量。 然后，通过上述信息统计这个容器的的分数，分数越高，成为友情链接容器的可能性越大。我的统计方法如下： 1、原始分数 = （站外链接 - 站内链接） * 1000，如果原始分数 &#60;= 0，直接否定。 2、链接文字所占比例 = 链接文字数 / 容器总文字数，用这个比例对原始分数进行正影响。 3、链接标签所占比例 = 链接标签数 / 容器总标签数，用这个比例对原始分数进行正影响。 4、如果最后得分少于1000，直接否定。（这样做是因为链接数太少，不考虑） 最后，对统计的所有容器的分数进行排序，得分最高的，选取为友情链接容器。 [...]]]></description>
			<content:encoded><![CDATA[<p>很久没有发一些有技术含量的文章了，最近发博文都有一种应付式的感觉，真对不起自己。感觉有时候是我沉醉于一样东西太长时间了，把我正常的生活节奏都打乱了，而却没有注意到这样子反而效率很低下。适时抽时间出来总结一下是蛮重要的！所以，以后决定每天都抽一个小时出来自我总结，觉得有所感想就写下来，有技术研究的，就给大家分享一下吧！</p>
<p>这两天在写下面的一个东西，用来搜集博客种子（Feed）的RSS或者Atom地址的。没有种子的博客不会被收录进来。因为只有Feed才对我有用！</p>
<p><img class="alignnone size-full wp-image-4946" title="feed" src="http://xiaoxia.org/upfiles/2012/05/feed.png" alt="" width="581" height="403" /></p>
<p>网站地址：<a href="http://feed.readself.com/" target="_blank">http://feed.readself.com/</a></p>
<p><span id="more-4945"></span><br />
<strong>我的需求</strong></p>
<p>因为我最近在做一个读书网站，需要从互联网博客频道中获取文章。之前通过人工添加了将近200个博客的Feed地址，定期更新以获取文章。如今阅读的基本功能已经完成，现在亟需的是大量的文章以供各种实验性的测试，例如文章分类，全文索引等，属于数据挖掘和模式匹配的范畴。</p>
<p>之前已经在构思用何种方式搜集互联网上的Feed来源，李劼杰同学的“<a href="http://www.fachun.net/" target="_blank">中国个人博客索引</a>”给了我很大的灵感。采用博客的“友情链接”的方式进行扩散搜索，而我仿效其方法采用BFS搜集博客的Feed。虽然我们俩做的是不同的方向，但是没想到这么巧合，他所分享的技术东西正是我所要研究的。</p>
<p>话说回来，我要采集的是博客的Feed地址，如何找呢？</p>
<p><strong>寻找Feed地址</strong></p>
<p>最近研究得出的方法是，从博客页面（可以是首页或者是文章页面）的HTML中，遍历所有link标签，采集如下的href属性。</p>
<blockquote><p>&lt;link rel="alternate" type="application/rss+xml" title="Xiaoxia[PG] &amp;raquo; Feed" href="http://xiaoxia.org/feed/" /&gt;</p></blockquote>
<p>大部分博客的Feed都是按照上面的代码提供，RSS是其中一种聚合类型，还有另外一种常见的是Atom。而常见的RSS还有两种不同的版本，当然这个不需要关心，因为我现在使用FeedParser来帮我采集RSS或者Atom里的内容（这个开源的FeedPaser在处理不正确的RSS时经常出错，需要自己修正代码）。</p>
<p>另外需要注意的是，有点link标签并没有 ref="alternate" 这个属性，同时还有可能把评论的Feed或者RPC的XML收录进来了。这个时候就需要加以区别了。</p>
<p>我目前采用一种评分的方法，即完全匹配标准格式的，打10分满分。遇到下列情况，则会被扣分：</p>
<p>1、没有 ref="alternate" 这个属性。</p>
<p>2、href中含有comment字符。</p>
<p>3、href中含有rpc字符。</p>
<p>4、href中含有rsd字符。</p>
<p>在对所有含有RSS或者Atom的link进行评分后，选取最高分作为Feed的地址。</p>
<p>另外需要注意的问题是，href不一定是完整的URL地址，有可能是相对路径，所以需要对其补全。</p>
<p><strong>寻找友情链接</strong></p>
<p>既然过友情链接进行扩散搜集，就需要对每个博客的友情链接李劼杰同学采用的是固定的模板匹配的方法，这种方法的限制是只能识别支持的博客的友情链接，而面对未知的博客类型，就无法提取友情链接了。所以会影响总体搜集的友情链接的数量。而我采用的方法是，基于概率统计的方式，定位友情链接的容器标签。</p>
<p>首先，枚举所有可以存放友情链接的容器，我取了div、table、ul这三个，当然还可能有其他的我还没有考虑到，但这三个已经涵盖了大部分的博客的情况。</p>
<p>对枚举的每个容器，统计所有的链接（a标签）。判断是否为站外链接，如果是，则增加链接数量，以及增加链接文字数量（为何要这个？因为图片超链接将会被排除），否则增加站内链接数。如果该站外链接为新窗口打开，则有相应的奖励，我目前是多算一次链接数量。</p>
<p>然后，通过上述信息统计这个容器的的分数，分数越高，成为友情链接容器的可能性越大。我的统计方法如下：</p>
<p>1、原始分数 = （站外链接 - 站内链接） * 1000，如果原始分数 &lt;= 0，直接否定。</p>
<p>2、链接文字所占比例 = 链接文字数 / 容器总文字数，用这个比例对原始分数进行正影响。</p>
<p>3、链接标签所占比例 = 链接标签数 / 容器总标签数，用这个比例对原始分数进行正影响。</p>
<p>4、如果最后得分少于1000，直接否定。（这样做是因为链接数太少，不考虑）</p>
<p>最后，对统计的所有容器的分数进行排序，得分最高的，选取为友情链接容器。</p>
<p>统计过程中，我所提及的正影响采用了下面的公式：</p>
<p>输出分数 = 输入分数  * 保持比例 + 输入分数 * （1 - 保持比例） * pow（输入比例，影响力）</p>
<p>为了方便大家理解，直接上代码：</p>
<pre class="python" name="code">
def affect(points, keep_ratio, ratio, power):
    keep = points * keep_ratio
    if ratio &gt;= 1.: return points
    return keep + (points - keep) * pow(ratio, power)

def calc_link_points(host, ul):
    # simplified host 不要子域名部分！
    parts = host.split('.')
    if parts[-2] in ('com','edu','net','gov','org'):
        host = '.'.join(host.split('.')[-3:])
    else:
        host = '.'.join(host.split('.')[-2:])

    link_density = linktext_count = totaltext_count = 0.001
    container_count = innerlink_count = 0.001
    for a in ul.findAll('a'):
        href = a.get('href', '')
        # 内部链接
        if not href or not href.lower().startswith('http') or host in href:
            innerlink_count += 1
            continue
        # 层次太深
        if urlparse(href)[2].strip('/').count('/') &gt;= 1 or '?' in href:
            continue
        link_density += 1
        linktext_count += len(a.text)
        if '_blank' == a.get('target'):
            link_density += 1
    # 统计容器字数
    for t in ul.recursiveChildGenerator():
        if type(t) is NavigableString:
            totaltext_count += len(t)
        else:
            container_count += 1
    points = (link_density - innerlink_count) * 1000
    if points &lt; 0: return 0

    points = affect(points, 0.1, linktext_count / totaltext_count, 2.)
    points = affect(points, 0.1, link_density / container_count, 1.)

    if points &lt; 1000: points = 0
    return points</pre>
<p>测试运行，提取 http://www.lijiejie.com 的友情链接。</p>
<blockquote><p>root@xiaoxia-pc:~/project/reader/test# python urls.py http://www.lijiejie.com<br />
Fetching http://www.lijiejie.com<br />
Parsing 36827 bytes<br />
Title 李劼杰的博客<br />
Found feed http://www.lijiejie.com/index.php/feed/<br />
12856.8536983 ul<br />
0 div<br />
0 div<br />
0 div<br />
......</p>
<p>Found links 11<br />
http://www.68flash.com/ 68flash<br />
http://hi.baidu.com/d7hack D7Hack<br />
http://www.rrgod.com/ Eddy Blog<br />
http://hi.baidu.com/15108971 hu1s4<br />
http://hi.baidu.com/282635791/ Xch40<br />
http://xiaoxia.org/ Xiaoxia[PG]<br />
http://www.fachun.net 中国博客索引<br />
http://chinahacker.blog.163.com/ 叱诧冰子<br />
http://www.lijiejie.cn 旺园阅览室<br />
http://haipo.me/ 杨海坡<br />
http://timepw.com 连文井</p></blockquote>
<p>友情链接的容器是一个ul，得分很高。其他容器直接被否决了，没有分数出来。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed3.png"><img class="alignnone size-full wp-image-4947" title="feed3" src="http://xiaoxia.org/upfiles/2012/05/feed3.png" alt="" width="439" height="451" /></a></p>
<p>下面测试 某熊 的 typecho，</p>
<blockquote><p>root@xiaoxia-pc:~/project/reader/test# python urls.py http://44670.org/<br />
Fetching http://44670.org/<br />
Parsing 11802 bytes<br />
Title 某熊[PG]<br />
Found feed http://44670.org/index.php/feed/atom/<br />
1649.51073438 ul<br />
1363.34619279 div<br />
0 div<br />
0 div<br />
0 ul<br />
0 ul<br />
......<br />
Found links 7<br />
http://sxkdz.0ginr.com/blog/ SXKDZ<br />
http://twd2.me 万呆博客<br />
http://iceboy.org/ iceboy[PG]<br />
http://whitefirer.org whitefirer[PG]<br />
http://hi.baidu.com/vi_orz vienna<br />
http://pm.mafom.com/ 愤怒的泡面<br />
http://newbiecoder.0ginr.com/blog NewbieCoder</p></blockquote>
<p>有一个ul和一个div的分数很接近，为什么呢？因为ul是被那个div包含的，而div多了一些额外标签和文字，所以分数没有ul那么高。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/feed1.png"><img class="alignnone size-full wp-image-4948" title="feed1" src="http://xiaoxia.org/upfiles/2012/05/feed1.png" alt="" width="402" height="375" /></a></p>
<p>对于常见的wordpress，zblog，pjblog等都能够准确定位友情链接的区域，那么非常用博客呢？例如 simple-is-better.com（python.cn），</p>
<blockquote><p>root@xiaoxia-pc:~/project/reader/test# python urls.py http://simple-is-better.com/<br />
Fetching http://simple-is-better.com/<br />
Parsing 36281 bytes<br />
Title python.cn(news, jobs)<br />
Found feed http://feed.feedsky.com/simple-is-better<br />
Abstract 200<br />
34359.9883395 ul<br />
28956.1843727 div<br />
8202.2453766 div<br />
0 div<br />
0 div<br />
0 div<br />
0 div<br />
0 div<br />
......<br />
Found links 26</p>
<p>http://hi.baidu.com/limodou/ limodou 的 Blog<br />
http://www.chenxiaoyu.org/ Smallfish 鱼哥<br />
http://techparty.org/ 珠三角技术沙龙<br />
http://www.autopart007.com/ China auto parts supplies<br />
http://www.mvmap.com/ 名城指南<br />
......</p></blockquote>
<p>这个34359分的ul和28956分的div，无论选哪个，都是成功定位到友情链接，毫无压力！</p>
<p>写到这里，我的Feed爬虫（8个进程）已经使用这套方法，工作了9个多小时，搜集2万多个博客的Feed地址 <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  因为burst的VPS内存才512MB，比较小，所以开8个进程就足够，还有留下内存跑mysql呢。如果是在一台性能好一点的机器上，开100多个进程同时抓取，不到1个小时就能抓2万个博客的Feed了。</p>
<p><strong>提取网页摘要</strong></p>
<p>对于网页摘要的提取，我没有花太多心思在这个上面。网页摘要是给 http://feed.readself.com 展示用的，对于我来说，没有太大的意义。但是简略的做了一个算法，提取文字最密集，超链接数目最小的容器标签，取其文本的前100个字。其中，用容器的超链接数目与网页总超链接数目的比例对统计文字得到分数进行负影响。我对文字进行了utf8编码是为了增加中文的权重，即一个中文字的权重等价于3个英文字符。</p>
<p>大致代码如下：</p>
<pre class="python" name="code">def find_text(body):
    candidates = []
    total_links = len(body.findAll('a')) + 0.001
    # 枚举文字容器
    for tag in ('div', 'section', 'article', 'td', 'li', 'dd', 'dt'):
        for x in body.findAll(tag):
            if type(x) is not Tag: continue
            points = len(x.text[:100].encode('utf8')) * 1000
            points = affect(points, 0.1, 1 - len(x.findAll('a')) * 1. / total_links, 1.)
            candidates.append((points, x))
    # 排序，取分数最高的容器
    candidates.sort(reverse = True)
    if candidates:
        return candidates[0][1]
    return body</pre>
<p>例如，对雄哥的博客进行提取网页摘要，</p>
<blockquote><p>root@xiaoxia-pc:~/project/reader/test# python urls.py http://ibaiyang.org<br />
Fetching http://ibaiyang.org<br />
Parsing 44596 bytes<br />
Title 白 杨<br />
Found feed http://www.ibaiyang.org/feed/<br />
Abstract 在看这边文章前，你还记得你班主任的名字么？一身中，我们或许永远记住那些曾经影响我们命运的人，老师当然在其中，而有如今的我，也正是感谢这些老师的关怀和肯定。昨天晚上，我一个朋友告诉我，他今天和我们初中班
</p></blockquote>
<p>这种方法提取到的网页摘要，通常是一篇文章的正文内容，对大量的中文网页采集的结果来看，效果很不错！但是对英文网页来看，还需要进一步的改进。</p>
<p>夜已深，对于我目前搜集Feed的技巧就介绍到这里！主要是想跟大家交流一下，因为我在这方面的经验还不多，相当于刚入门，所以希望有人站出来，给一些意见或者一些好的提议 <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/05/12/blog-feed-crawler-python/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>jQueryUI写一个调整分类的拖放效果 [附Demo]</title>
		<link>http://xiaoxia.org/2012/05/06/jqueryui-drag-drop-demo/</link>
		<comments>http://xiaoxia.org/2012/05/06/jqueryui-drag-drop-demo/#comments</comments>
		<pubDate>Sat, 05 May 2012 17:51:37 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Internet]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4936</guid>
		<description><![CDATA[最近，想用jQuery做一个网页的树目录结构，并且可以使用鼠标拖动调整选项的位置。我在网上找了一下插件，基本上看了好几款比较著名的，都觉得代码太复杂了或者界面太丑了等各种不符合我的要求。所以还是自己动手丰衣足食，还是坚持简单就是美的代码风格。 Demo演示 试试在iframe里嵌入一个测试页面，你可以使用鼠标拖动项目，调整分类： 当然，这并不是我要的最终效果，只能说它已经实现了一个我想要的拖放效果。我要求的在这个基础上，还要增加自动排序，位置变更后恢复之前元素bind的jQuery事件等。 代码 代码如下，如要复制，请先查看纯文本版本！ &#60;!DOCTYPE html&#62; &#60;html&#62; &#60;head&#62; &#60;title&#62;Drag &#38; Drop Test&#60;/title&#62; &#60;meta http-equiv=&#34;content-type&#34; content=&#34;text/html; charset=UTF-8&#34;&#62; &#60;script type=&#34;text/javascript&#34; src=&#34;https://readself.com/static/js/jquery.min.js?v=52337&#34;&#62;&#60;/script&#62; &#60;script type=&#34;text/javascript&#34; src=&#34;https://readself.com/static/js/jquery-ui.min.js?v=ab482&#34;&#62;&#60;/script&#62; &#60;link rel=&#34;stylesheet&#34; type=&#34;text/css&#34; href=&#34;https://readself.com/static/css/smoothness/jquery-ui.css?v=af3ef&#34; /&#62; &#60;style type=&#34;text/css&#34;&#62; li {cursor: pointer} .menu_hover {background-color: #d0d0d0;} #menu p{margin: 5px 0 5px 0;} &#60;/style&#62; &#60;body&#62; &#60;ul id=&#34;menu&#34;&#62; &#60;li class=&#34;folder&#34;&#62; &#60;p&#62;Fruits&#60;/p&#62; &#60;ul&#62; &#60;li&#62;Apple&#60;/li&#62; &#60;li&#62;Pear&#60;/li&#62; &#60;li&#62;Banana&#60;/li&#62; &#60;/ul&#62; [...]]]></description>
			<content:encoded><![CDATA[<p>最近，想用jQuery做一个网页的树目录结构，并且可以使用鼠标拖动调整选项的位置。我在网上找了一下插件，基本上看了好几款比较著名的，都觉得代码太复杂了或者界面太丑了等各种不符合我的要求。所以还是自己动手丰衣足食，还是坚持简单就是美的代码风格。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/rr18.png"><img src="http://xiaoxia.org/upfiles/2012/05/rr18.png" alt="" title="rr18" width="365" height="324" class="alignnone size-full wp-image-4937" /></a></p>
<p><span id="more-4936"></span></p>
<p><strong>Demo演示</strong></p>
<p>试试在iframe里嵌入一个测试页面，你可以使用鼠标拖动项目，调整分类：</p>
<p><iframe width="300px" height="300px" src="http://xiaoxia.org/sub/jqueryui-dragdrop.html" alt="dragdrop" border="0"><br />
</iframe></p>
<p>当然，这并不是我要的最终效果，只能说它已经实现了一个我想要的拖放效果。我要求的在这个基础上，还要增加自动排序，位置变更后恢复之前元素bind的jQuery事件等。</p>
<p><strong>代码</strong></p>
<p>代码如下，如要复制，请先查看纯文本版本！</p>
<pre name="code" class="php">
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Drag &amp; Drop Test&lt;/title&gt;
&lt;meta http-equiv=&quot;content-type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
&lt;script type=&quot;text/javascript&quot;
src=&quot;https://readself.com/static/js/jquery.min.js?v=52337&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;
src=&quot;https://readself.com/static/js/jquery-ui.min.js?v=ab482&quot;&gt;&lt;/script&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot;
href=&quot;https://readself.com/static/css/smoothness/jquery-ui.css?v=af3ef&quot; /&gt;
&lt;style type=&quot;text/css&quot;&gt;
li {cursor: pointer}
.menu_hover {background-color: #d0d0d0;}
#menu p{margin: 5px 0 5px 0;}
&lt;/style&gt;
&lt;body&gt;
&lt;ul id=&quot;menu&quot;&gt;
    &lt;li class=&quot;folder&quot;&gt;
        &lt;p&gt;Fruits&lt;/p&gt;
        &lt;ul&gt;
            &lt;li&gt;Apple&lt;/li&gt;
            &lt;li&gt;Pear&lt;/li&gt;
            &lt;li&gt;Banana&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li class=&quot;folder&quot;&gt;&lt;p&gt;Vegetables&lt;/p&gt;
        &lt;ul&gt;
            &lt;li&gt;Tomato&lt;/li&gt;
            &lt;li&gt;Potato&lt;/li&gt;
            &lt;li&gt;Cucumber&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
    &lt;li class=&quot;folder&quot;&gt;&lt;p&gt;Meet&lt;/p&gt;
        &lt;ul&gt;
            &lt;li&gt;Beaf&lt;/li&gt;
            &lt;li&gt;Pork&lt;/li&gt;
            &lt;li&gt;Chicken&lt;/li&gt;
        &lt;/ul&gt;
    &lt;/li&gt;
&lt;/ul&gt;

&lt;script&gt;
$('#menu li').disableSelection();
$('li', $('#menu ul')).draggable({revert: 'invalid', helper: 'clone'});
$('#menu .folder').droppable({
    hoverClass: &quot;menu_hover&quot;,
    drop: function(event, ui){
        if(ui.draggable.parents('.folder').get(0) == $(this).get(0))
            return ;
        $('ul', this).append(ui.draggable.clone());
        ui.draggable.remove();
        $('li', this).draggable({remove: 'invalid', helper: 'clone'});
    }
});
$('#menu .folder p').click(function(){
    $(this).next().toggle();
});
&lt;/script&gt;
</pre>
<p>在编写网页上我还是菜鸟，欢迎网页大牛指点迷津！！！</p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/05/06/jqueryui-drag-drop-demo/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>听说这女人要开网店，大家支持下</title>
		<link>http://xiaoxia.org/2012/05/03/jessicas-shop/</link>
		<comments>http://xiaoxia.org/2012/05/03/jessicas-shop/#comments</comments>
		<pubDate>Wed, 02 May 2012 16:14:14 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[我的生活]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4930</guid>
		<description><![CDATA[如题！ 官方微博 @小云雀2012 官方网店 http://little-skylark.taobao.com/ &#160;]]></description>
			<content:encoded><![CDATA[<p>如题！</p>
<p>官方微博 <a href="http://weibo.com/u/2784976690" target="_blank">@小云雀2012</a></p>
<p>官方网店 <a href="http://little-skylark.taobao.com/" target="_blank">http://little-skylark.taobao.com/</a></p>
<p><a href="http://xiaoxia.org/upfiles/2012/05/a5ff5f32gw1dskbasgdaij.jpg"><img class="alignnone size-medium wp-image-4931" title="a5ff5f32gw1dskbasgdaij" src="http://xiaoxia.org/upfiles/2012/05/a5ff5f32gw1dskbasgdaij-506x700.jpg" alt="" width="506" height="700" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/05/03/jessicas-shop/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>写了个Python脚本监控nginx进程</title>
		<link>http://xiaoxia.org/2012/04/30/python-nginx-monitor/</link>
		<comments>http://xiaoxia.org/2012/04/30/python-nginx-monitor/#comments</comments>
		<pubDate>Sun, 29 Apr 2012 18:08:32 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[我的代码]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4925</guid>
		<description><![CDATA[接上一文用iptables让SSH服务对陌生人说不。还是有点担心这个学期内，nginx可能会因为系统各种原因而出现异常退出，导致Web服务暂停。所以，又来了一个方案。 #!/usr/bin/env python import os, sys, time while True: time.sleep(3) try: ret = os.popen('ps -C nginx -o pid,cmd').readlines() if len(ret) < 2: print "nginx process killed, restarting service in 3 seconds." time.sleep(3) os.system("service nginx restart") except: print "Error", sys.exc_info()[1] 设置文件可执行属性，加入到/etc/rc.local，总算放心了。 这种方法还可以监控别的进程，我相信应该有现成的监控软件，但是我觉得写个脚本更方便。]]></description>
			<content:encoded><![CDATA[<p>接上一文<a href="http://xiaoxia.org/2012/04/30/iptables-sshd-firewall/" target="_blank">用iptables让SSH服务对陌生人说不</a>。还是有点担心这个学期内，nginx可能会因为系统各种原因而出现异常退出，导致Web服务暂停。所以，又来了一个方案。</p>
<pre name="code" class="python">
#!/usr/bin/env python
import os, sys, time

while True:
    time.sleep(3)
    try:
        ret = os.popen('ps -C nginx -o pid,cmd').readlines()
        if len(ret) < 2:
            print "nginx process killed, restarting service in 3 seconds."
            time.sleep(3)
            os.system("service nginx restart")
    except:
        print "Error", sys.exc_info()[1]
</pre>
<p>设置文件可执行属性，加入到/etc/rc.local，总算放心了。<br />
这种方法还可以监控别的进程，我相信应该有现成的监控软件，但是我觉得写个脚本更方便。</p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/04/30/python-nginx-monitor/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>用iptables让SSH服务对陌生人说不</title>
		<link>http://xiaoxia.org/2012/04/30/iptables-sshd-firewall/</link>
		<comments>http://xiaoxia.org/2012/04/30/iptables-sshd-firewall/#comments</comments>
		<pubDate>Sun, 29 Apr 2012 17:37:52 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4920</guid>
		<description><![CDATA[今晚老师跟我说服务器的Web挂了，但是FTP可以用。我登录了这个OpenVZ的VPS，发现nginx进程没了。为什么会发生这么神奇的事情呢？ 我在/var/log/nginx下翻了日志文件，没有发现任何出错信息。然后想会不会是系统内存超了，被OpenVZ内核KILL了呢？查了一下，果然发现： uid resource held maxheld barrier limit failcnt 3004536: kmemsize 3626521 4652581 51200000 51200000 0 lockedpages 0 0 2048 2048 0 privvmpages 34041 131231 131200 262200 3 shmpages 1281 1297 128000 128000 0 私有虚拟页面privvmpages的数值超了，有3次失败请求。一个页面4KB，所以这个VPS的内存是512M. 我在这个VPS上只开启了nginx，vsftpd，mysqld，php-cgi，xxfpm等服务，不可能占用那么多内存吧。php的进程数量是用自己写的xxfpm限制死了，只能有3个进程。这些所有的服务一共才占用100多MB内存，怎么可能超了512M呢？ 而nginx占用的内存真的很小呀， root 22333 0.0 0.1 4988 716 ? Ss Apr29 0:00 nginx: master process /usr/sbin/nginx www-data 22334 0.0 0.3 [...]]]></description>
			<content:encoded><![CDATA[<p>今晚老师跟我说服务器的Web挂了，但是FTP可以用。我登录了这个OpenVZ的VPS，发现nginx进程没了。为什么会发生这么神奇的事情呢？</p>
<p>我在/var/log/nginx下翻了日志文件，没有发现任何出错信息。然后想会不会是系统内存超了，被OpenVZ内核KILL了呢？查了一下，果然发现：</p>
<blockquote><p>uid resource held maxheld barrier limit failcnt<br />
3004536: kmemsize 3626521 4652581 51200000 51200000 0<br />
lockedpages 0 0 2048 2048 0<br />
privvmpages 34041 131231 131200 262200 3<br />
shmpages 1281 1297 128000 128000 0</p></blockquote>
<p>私有虚拟页面privvmpages的数值超了，有3次失败请求。一个页面4KB，所以这个VPS的内存是512M.</p>
<p>我在这个VPS上只开启了nginx，vsftpd，mysqld，php-cgi，xxfpm等服务，不可能占用那么多内存吧。php的进程数量是用自己写的<a href="http://xiaoxia.org/2011/02/01/xxfpm-wrote-a-fastcgi-process-manager/">xxfpm</a>限制死了，只能有3个进程。这些所有的服务一共才占用100多MB内存，怎么可能超了512M呢？<br />
<span id="more-4920"></span><br />
而nginx占用的内存真的很小呀，</p>
<blockquote>
<pre>root 22333 0.0 0.1 4988 716 ? Ss Apr29 0:00 nginx: master process /usr/sbin/nginx
www-data 22334 0.0 0.3 5524 1740 ? S Apr29 0:00 nginx: worker process</pre>
</blockquote>
<p>再看了一下/var/log下的日志文件，发现auth.log文件体积很大，我开始怀疑是不是被枚举root密码了。因为sshd会给每个连接fork一个进程，所以当被大量攻击的时候，ssh的进程会变得很多！至于sshd自身有没有对这个数量进行限制，我不是很清楚！</p>
<blockquote><p>...<br />
Apr 29 11:39:02 293621 CRON[21809]: pam_unix(cron:session): session closed for user root<br />
Apr 29 12:09:01 293621 CRON[21843]: pam_unix(cron:session): session opened for user root by (uid=0)<br />
Apr 29 12:09:01 293621 CRON[21843]: pam_unix(cron:session): session closed for user root<br />
Apr 29 12:25:01 293621 CRON[21861]: pam_unix(cron:session): session opened for user root by (uid=0)<br />
Apr 29 12:25:01 293621 CRON[21861]: pam_unix(cron:session): session closed for user root<br />
Apr 29 12:28:58 293621 sshd[21867]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=208.115.207.253 user=root<br />
Apr 29 12:28:58 293621 sshd[21866]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=208.115.207.253 user=root<br />
Apr 29 12:29:01 293621 sshd[21867]: Failed password for root from 208.115.207.253 port 58931 ssh2<br />
Apr 29 12:29:01 293621 sshd[21866]: Failed password for root from 208.115.207.253 port 56639 ssh2<br />
Apr 29 12:39:01 293621 CRON[21879]: pam_unix(cron:session): session opened for user root by (uid=0)<br />
Apr 29 12:39:01 293621 CRON[21879]: pam_unix(cron:session): session closed for user root<br />
Apr 29 13:09:01 293621 CRON[21913]: pam_unix(cron:session): session opened for user root by (uid=0)<br />
Apr 29 13:09:01 293621 CRON[21913]: pam_unix(cron:session): session closed for user root<br />
Apr 29 13:25:01 293621 CRON[21931]: pam_unix(cron:session): session opened for user root by (uid=0)<br />
Apr 29 13:25:01 293621 CRON[21931]: pam_unix(cron:session): session closed for user root<br />
Apr 29 13:39:01 293621 CRON[21947]: pam_unix(cron:session): session opened for user root<br />
...</p></blockquote>
<p>为了对付这种攻击，网上查了，有关于限制IP、用户连接数的，也有关于取消root账户密码登录，采用证书认证的，之前写过一篇文章<a href="http://xiaoxia.org/2011/10/31/login-remote-ssh-without-passwords/" target="_blank">免口令登录远程SSH服务</a>就是使用证书登录的。但是我觉得最有效的方法就是在防火墙里设置IP白名单了。这样既避免了产生大量的流量，也不会产生sshd的连接进程。</p>
<p>所以，果断iptables，添加两个我常用的IP段，其他网段的数据包都DROP了，而不是REJECT（REJECT还要发送ICMP回应包给连接方）。</p>
<blockquote>
<pre># iptables -A INPUT -p tcp --dport 22 -s 120.0.0.0/8 -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -s 183.0.0.0/8 -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j DROP</pre>
</blockquote>
<p>尝试在另外一个机子连接这个VPS，数据包被成功DROP了。</p>
<blockquote>
<pre>root@293621:~# iptables -vL
Chain INPUT (policy ACCEPT 36 packets, 6257 bytes)
pkts bytes target prot opt in out source destination
222 16280 ACCEPT tcp -- any any 120.0.0.0/8 anywhere tcp dpt:ssh
0 0 ACCEPT tcp -- any any 183.0.0.0/8 anywhere tcp dpt:ssh
4 240 DROP tcp -- any any anywhere anywhere tcp dpt:ssh</pre>
</blockquote>
<p>&nbsp;</p>
<p>So, 希望nginx不会再崩了 <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/04/30/iptables-sshd-firewall/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>在路由器上写CMCC自动登录验证脚本</title>
		<link>http://xiaoxia.org/2012/04/28/mini-router-auto-login-cmcc/</link>
		<comments>http://xiaoxia.org/2012/04/28/mini-router-auto-login-cmcc/#comments</comments>
		<pubDate>Fri, 27 Apr 2012 16:03:30 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[我的代码]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4909</guid>
		<description><![CDATA[今天入手了一个新的路由器，160RMB，特点是体积很小，像个火柴盒，但有64MB内存，安装openWRT（Linux）操作系统，内核比较新。玩了一下，功能很强大，跟那些几千元的大型路由器有的比呀！ 如下图模型： 买回来马上看看配置如何， 看起来蛮不错的，内存也很足够，能做一般的web服务了。目前我博客的web服务占用的内存也就在60MB左右，如果不用php和mysql的话，web服务只需要30MB就够！ &#160; 刚买回来的路由，最想做的第一件事当然是在上面安装Python了，在这个基础上，我以前的一堆代理程序和VPN程序都能够跑了。 然而悲剧的是，我刚想用opkg安装python软件包，系统提示我仅剩下200多kb内存空间了，无法安装成功。看来这个内置的Flash容量太少了，装个python当然不行。所以，我把我经常戴在钥匙上的U盘拿下来了，在路由系统里用ext2格式化了一次。把系统软件转移到了U盘上（做法很简单，直接把python安装到u盘，然后在环境变量的PATH里设置U盘上的bin目录即可）。 root@OpenWrt:~# python -V Python 2.7.3rc2 &#160; 本来打算今晚写好一个基于IPv6通信的VPN程序，放在实验室里跑的，这样在宿舍就能够免费撑实验室的网而且不断网了！但是折腾了一个晚上，都无法解决一个很诡异的错误： [Errno 81] File descriptor in bad state. Google了也找不到解决方案。所以无法在python里创建tun设备了，VPN也没戏了。奇怪的是，我用ip tuntap命令是可以创建和配置的，难道是我的python库有问题？？？ &#160; VPN没有搞成，最后搞了一个CMCC的无线中继。而且免去了CMCC的登录验证，因为验证已经在路由里完成了。我的做法是，在原有的无线网的基础上，增加另外一个无线网络，但是采用客户端模式，而不是接入点模式，openWRT的配置操作很简单，几步就完成了。 但是，CMCC的登录验证代码还是要自己写的。所以还是花了时间去研究一下登录过程。 代码如下： #!/usr/bin/env python import cookielib, urllib2 import re import os import random import time username = '' passwd = '' cj = cookielib.CookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) test = opener.open('http://xiaoxia.org') [...]]]></description>
			<content:encoded><![CDATA[<p>今天入手了一个新的路由器，160RMB，特点是体积很小，像个火柴盒，但有64MB内存，安装openWRT（Linux）操作系统，内核比较新。玩了一下，功能很强大，跟那些几千元的大型路由器有的比呀！</p>
<p>如下图模型：</p>
<p><a href="http://xiaoxia.org/upfiles/2012/04/rr8.png"><img class="alignnone size-full wp-image-4910" title="rr8" src="http://xiaoxia.org/upfiles/2012/04/rr8.png" alt="" width="389" height="261" /></a></p>
<p><span id="more-4909"></span><br />
买回来马上看看配置如何，</p>
<p><a href="http://xiaoxia.org/upfiles/2012/04/rr5.png"><img class="alignnone size-full wp-image-4912" title="rr5" src="http://xiaoxia.org/upfiles/2012/04/rr5.png" alt="" width="463" height="330" /></a></p>
<p>看起来蛮不错的，内存也很足够，能做一般的web服务了。目前我博客的web服务占用的内存也就在60MB左右，如果不用php和mysql的话，web服务只需要30MB就够！</p>
<p>&nbsp;</p>
<p><a href="http://xiaoxia.org/upfiles/2012/04/rr6.png"><img class="alignnone size-full wp-image-4913" title="rr6" src="http://xiaoxia.org/upfiles/2012/04/rr6.png" alt="" width="480" height="152" /></a></p>
<p>刚买回来的路由，最想做的第一件事当然是在上面安装Python了，在这个基础上，我以前的一堆代理程序和VPN程序都能够跑了。</p>
<p>然而悲剧的是，我刚想用opkg安装python软件包，系统提示我仅剩下200多kb内存空间了，无法安装成功。看来这个内置的Flash容量太少了，装个python当然不行。所以，我把我经常戴在钥匙上的U盘拿下来了，在路由系统里用ext2格式化了一次。把系统软件转移到了U盘上（做法很简单，直接把python安装到u盘，然后在环境变量的PATH里设置U盘上的bin目录即可）。</p>
<blockquote><p>root@OpenWrt:~# python -V<br />
Python 2.7.3rc2</p></blockquote>
<p><a href="http://xiaoxia.org/upfiles/2012/04/rr7.png"><img class="alignnone size-full wp-image-4911" title="rr7" src="http://xiaoxia.org/upfiles/2012/04/rr7.png" alt="" width="467" height="352" /></a></p>
<p>&nbsp;</p>
<p>本来打算今晚写好一个基于IPv6通信的VPN程序，放在实验室里跑的，这样在宿舍就能够免费撑实验室的网而且不断网了！但是折腾了一个晚上，都无法解决一个很诡异的错误：</p>
<blockquote><p>[Errno 81] File descriptor in bad state.</p></blockquote>
<p>Google了也找不到解决方案。所以无法在python里创建tun设备了，VPN也没戏了。奇怪的是，我用ip tuntap命令是可以创建和配置的，难道是我的python库有问题？？？</p>
<p>&nbsp;</p>
<p>VPN没有搞成，最后搞了一个CMCC的无线中继。而且免去了CMCC的登录验证，因为验证已经在路由里完成了。我的做法是，在原有的无线网的基础上，增加另外一个无线网络，但是采用客户端模式，而不是接入点模式，openWRT的配置操作很简单，几步就完成了。</p>
<p><a href="http://xiaoxia.org/upfiles/2012/04/rr2.png"><img class="alignnone size-full wp-image-4914" title="rr2" src="http://xiaoxia.org/upfiles/2012/04/rr2.png" alt="" width="252" height="215" /></a></p>
<p>但是，CMCC的登录验证代码还是要自己写的。所以还是花了时间去研究一下登录过程。</p>
<p>代码如下：</p>
<pre class="python" name="code">#!/usr/bin/env python
import cookielib, urllib2
import re
import os
import random
import time

username = ''
passwd = ''

cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))

test = opener.open('http://xiaoxia.org')
data = test.read()
userip = re.search(r'NAME="wlanuserip" value="(.+)"&gt;', data).group(1)
acname = re.search(r'NAME="wlanacname" value="(.+)"&gt;', data).group(1)
acip = re.search(r'NAME="wlanacip" value="(.+)"&gt;', data).group(1)

url = os.path.join(os.path.dirname(test.url), 'index.jsp')
data = 'wlanuserip=%s&amp;wlanacname=%s&amp;wlanacip=%s' % (userip, acname, acip)
print 'opening', url, data
data = opener.open(url, data).read()

url = os.path.join(os.path.dirname(test.url), 'jsp/do_login.jsp')
data = 'bpssUSERNAME=%s&amp;bpssBUSPWD=%s&amp;' +\
 'Submit=\xb5\xc7\xc2\xbc&amp;bpssLoginType=1' % (username, passwd)
print 'opening', url, data
data = opener.open(url, data).read()
print 'result', data</pre>
<p>代码是在路由器上打的，所以看起来比较乱，但是步骤不多。如果已经登录成功，则肯定可以打开xiaoxia.org，所以后面的步骤都不起作用。如果未登录，会被跳转到登录页面，提交帐号登录即可。</p>
<p>为了能够让路由器保持CMCC的在线状态，把上面的脚本加入了crontab，设置为10分钟自动执行一次该脚本。所以今晚的努力还是没有白费，以后在笔记本或者手机上可以不用输入帐号使用无线网了，也不用担心老登不上CMCC的那个bug了。。。</p>
<p>That's all. Thank you <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/04/28/mini-router-auto-login-cmcc/feed/</wfw:commentRss>
		<slash:comments>65</slash:comments>
		</item>
		<item>
		<title>SCUT.TK域名已经失效，请使用scut.xiaoxia.org</title>
		<link>http://xiaoxia.org/2012/04/21/scut-tk-is-lost/</link>
		<comments>http://xiaoxia.org/2012/04/21/scut-tk-is-lost/#comments</comments>
		<pubDate>Sat, 21 Apr 2012 12:29:44 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[Internet]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4905</guid>
		<description><![CDATA[tk域名总是不好用，出现各种各样的问题，所以前些天代理失效了。 可能是因为这个域名是内网使用的，所以tk的人访问不了就把域名给取消了！ Dear Xiaoxia Huang, The Dot TK Abuse and Copyright Infringement department has visited your website today. Unfortunately we have to say that today we cancelled your domain SCUT.TK. 为了方便大家以后使用，暂时用我的一个子域名代替吧！ scut.xiaoxia.org IPv4和IPv6都可以访问。另外透露一个好消息，虽然华工C12宿舍晚上12点后会断网，但是IPv6仍然可以用，所以有IPv6的同学仍然可以使用这个代理哦！搜狗的代理对无法访问教育网用户来说还是挺方便的。 我研究过B3实验楼那边为何会有国际流量，能够访问国外的网站，原因竟然是，访问国外网站走的是广州电信的线路！看来用的是多重网络？所以，现在有的同学在B3那边有实验机器的话，都能够使用IPv6建立一个VPN，然后在宿舍就可以不断网，而且还能上国外网站了，哈哈！！！对于我这种长期撑网的人来说，也还是挺好的！主要是移动的CMCC有时候也太不给力了，所以有个稳定的校园网也挺方便]]></description>
			<content:encoded><![CDATA[<p>tk域名总是不好用，出现各种各样的问题，所以前些天代理失效了。<br />
可能是因为这个域名是内网使用的，所以tk的人访问不了就把域名给取消了！</p>
<blockquote><p>
Dear Xiaoxia Huang,</p>
<p>The Dot TK Abuse and Copyright Infringement department has<br />
visited your website today.</p>
<p>Unfortunately we have to say that today we cancelled your domain SCUT.TK.
</p></blockquote>
<p>为了方便大家以后使用，暂时用我的一个子域名代替吧！<br />
<span id="more-4905"></span><br />
scut.xiaoxia.org</p>
<p>IPv4和IPv6都可以访问。另外透露一个好消息，虽然华工C12宿舍晚上12点后会断网，但是IPv6仍然可以用，所以有IPv6的同学仍然可以使用这个代理哦！搜狗的代理对无法访问教育网用户来说还是挺方便的。</p>
<p>我研究过B3实验楼那边为何会有国际流量，能够访问国外的网站，原因竟然是，访问国外网站走的是广州电信的线路！看来用的是多重网络？所以，现在有的同学在B3那边有实验机器的话，都能够使用IPv6建立一个VPN，然后在宿舍就可以不断网，而且还能上国外网站了，哈哈！！！对于我这种长期撑网的人来说，也还是挺好的！主要是移动的CMCC有时候也太不给力了，所以有个稳定的校园网也挺方便 <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/04/21/scut-tk-is-lost/feed/</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>用水清洗了CPU风扇，解决了笔记本散热问题</title>
		<link>http://xiaoxia.org/2012/04/14/water-cpu-fan-and-laptop-heat/</link>
		<comments>http://xiaoxia.org/2012/04/14/water-cpu-fan-and-laptop-heat/#comments</comments>
		<pubDate>Sat, 14 Apr 2012 13:18:33 +0000</pubDate>
		<dc:creator>Xiaoxia</dc:creator>
				<category><![CDATA[我的生活]]></category>

		<guid isPermaLink="false">http://xiaoxia.org/?p=4902</guid>
		<description><![CDATA[我用的Y460笔记本散热一直比较差，最近已经到了无法忍受的地步了。开机一段时间后，即使不怎么运行软件，温度也很高，底座很烫手，真的可以煎鸡蛋的！这机子温度一高起来，不会死机，而是CPU自动降频。导致的结果是打开网页，CPU用满了，等了半天还没反应过来。 本来还想买个散热器来解决这个问题，因为上个月在北京的时候就是用着散热器才不卡机。但是使用外部的风扇来降温不是根本的解决办法，换个地方上网还是会有这个问题。所以，决定自己拆开笔记本，把风扇取了出来！还挺好拆的，拆了之后看到风扇上已经积满了灰尘，吹也吹不掉，只能用水冲，用刷子擦了。清洗过后的风扇轻了很多，转起来也很给力了！ 今天开了一天的笔记本也没有发现温度特别高，所以这个问题已经完美解决，不再困扰我了]]></description>
			<content:encoded><![CDATA[<p>我用的Y460笔记本散热一直比较差，最近已经到了无法忍受的地步了。开机一段时间后，即使不怎么运行软件，温度也很高，底座很烫手，真的可以煎鸡蛋的！这机子温度一高起来，不会死机，而是CPU自动降频。导致的结果是打开网页，CPU用满了，等了半天还没反应过来。</p>
<p>本来还想买个散热器来解决这个问题，因为上个月在北京的时候就是用着散热器才不卡机。但是使用外部的风扇来降温不是根本的解决办法，换个地方上网还是会有这个问题。所以，决定自己拆开笔记本，把风扇取了出来！还挺好拆的，拆了之后看到风扇上已经积满了灰尘，吹也吹不掉，只能用水冲，用刷子擦了。清洗过后的风扇轻了很多，转起来也很给力了！</p>
<p>今天开了一天的笔记本也没有发现温度特别高，所以这个问题已经完美解决，不再困扰我了 <img src='http://xiaoxia.org/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://xiaoxia.org/2012/04/14/water-cpu-fan-and-laptop-heat/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
	</channel>
</rss>

