假设我们有一个组件
1 | class Square extends React.Component { |
然后在另一个组件里调用
1 | class Board extends React.Component { |
假设我们有一个组件
1 | class Square extends React.Component { |
然后在另一个组件里调用
1 | class Board extends React.Component { |
N-Gram,或者称为N元模型,是NLP一种方法。本文主要用于展示N-Gram在评估字符串之间的差异程度的使用方法,并提供一种基于N-Gram的Bi-Gram实现。
N-Gram方法主要是通过定义N-Gram距离来体现两个字符串之间的相似度。N-Gram通过将两个字符串切分成$x$个$n$长度的子串,并通过比较字串的之间的命中次数,来决定两个字符串的距离。这是因为我们认为,一个单字出现的概率与它之前的n-1个单字有关,而与任何其它单字都没有关系,那么如果我们有一个m个词组成的句子,其概率应为
$$
P(w_1,w_2,…w_m)
$$
那么根据链式法则,有
$$
P(w_1,w_2,…w_m) = p(w_1)×p(w_2|w_1)×p(w_3|w_2,w_1)×…p(w_m|w_1,…,w_{m-1})
$$
根据马尔科夫链的“无记忆”性质,我们假设这个链中的单字只与前方其$n-1$个单字有关,有
$$
P(w_1,w_2,…w_m) =\prod {i=1}^{m}P(w_i|w{i-1})
$$
我们以Bi-Gram(即$N=2$)方法为例
以一个字符串$s$为例,假设这个s的字串为”elpsycongroo”,那么一个Bi-Gram的拆分就为
$el, lp, ps, sy, yc, co, on, ng, gr, ro, oo, o$
我们又有一子串t,为”elpsy”,Bi-Gram拆分为$el,lp,ps,sy,y$。
以非重复的N-Gram分词来定义N-Gram距离,我们有如下公式。
$$
|GN_s|+|GN_t|−2×|GN_s∩GN_t|
$$
那么此例中
$$
\underline {el},\underline {lp},\underline {ps},\underline {sy},yc, co, on, ng, gr, ro, oo, o
$$
$$
\underline {el},\underline {lp},\underline {ps},\underline {sy},y
$$
这个project用于爬取YorkBBS上完整的住房信息,并将其生成一个html,放入apache2的服务器下,使之可以在任何地方查看筛选好的信息。
YorkBBS采用的是动态网页加载,如果采用http解析器直接采集DOM结构的话,只能得到一个参杂了JS代码的HTML结构。这里有两个思路:
使用诸如PhantomnJS之类的库,等待网页加载完成才进行DOM读取
使用Chrome DevTool,通过Network功能查找和服务器端的通讯从而判断出数据的API接口,并通过伪造Header获取相应的信息
这里我们采用第二个思路,首先打开Chrome DevTool 的Network标签,刷新目标网页,观察和服务器目标中的通讯。我们很快发现了这个Header:
Android Studio 在高版本后自带了Jsoup解析器,要使用Jsoup解析器,首先要在
1 |
|
1 | <!-- more --> |
需要注意的是,Jsoup.connect后需要加get()才能取得解析结果,而timeout则要加在两者之间。
这个function 返回的Document格式是Jsoup独有的格式。所以需要导入import org.jsoup.nodes.Document
才不会报错。
首先分析网页结构
需要抓取的结构通过分析我们可以看出位于<ul></ul>
内 , 此时令Document doc = getDocument(url)
添加Jsoup选择器Element ul = doc.select("ul").first()
这段代码的意思是从整个被解析出的html文件中选取第一个ul作为Element。需要注意的是,这个网页中含有两个<ul>
element 而如果不使用.first()
去选择第一个ul作为element则必须使用Elements
作为数据容器。
此时我们已经选择第一个<ul>
作为目标,使用 Elements elements= ul.select("li");
选取ul内所有的li作为目标。 迭代循环并输出每一个element的内容。
在Android中,原始的主线程不允许参与与网络有关的模块运行,因为非常容易造成卡顿,那么要运行刚刚的程序,必须开启一个新的线程。
1 | new Thread(){ |
而如果要更新View,则必须使用Handler才能进行
1 | Handler handler=new Handler(); |
但是如果直接使用两者来setContentoftextView就会遇到一个问题:报错
1 | android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. |
翻译过来就是,只有创建view的那个线程(这里是主线程)才能跟新view,而我们创建的子线程new thread如果直接运行setContentOfTextView则会报错。
这里就要使用这种方法才能避开这个问题
1 | new Thread(){ |
通过在handler.post里再创建一个新的Runnable event在里面跑setContentofTextView就可以成功的避开这个问题了。
(1)在设置textView的时候,如果加一行textView.setMovementMethod(ScrollingMovementMethod.getInstance());
则textview可以触屏滚动
(2)在制作这个简单的爬虫APP的时候,我并没有考虑脱离网络的情况,实际上,如果不加入判断手机是否有网络的代码,则这个APP会直接崩溃,推荐在之后的APP里加入判断手机是否有Wifi或者是数据的功能。
Update your browser to view this website correctly. Update my browser now