bsspider

爬虫

hipda爬虫和关键词统计

标签(空格分隔): 爬虫


忘了是怎么突发奇想,大概还是“闲着也是闲着”又或者“fifa经理人模式不做些什么总是不好的”这一类想法,所以就打算做个hipda相关的爬虫。
可能涉及到的知识
1.通过chrome抓包,并且模拟登陆
2.对cookielib的使用
3.对multiprocessing的使用
4.使用mmeg进行分词,再用jieba进行关键词处理。

首先就是先把必要的库安装好,这里中文分词推荐mmseg,基于c,速度快,支持搜狗细胞词库转化为字典。关键词分析可以用jieba,也可以自己写词频统计再弄个排序什么的。推荐前者,因为有词性支持。

1.通过chrom抓包,模拟登陆,以及保存cookie
这里碰到的第一个问题就是登陆的时候会跳转页面,包不好抓。解决方法也很简单——故意输错用户名。一开始想的是故意输错密码,但是密码是加密的。
此处输入图片的描述
“from data”部分就是需要提交的数据啦。
下面就开始用python构造登陆脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#coding=utf-8
import urllib2
import urllib
import cookielib
import re
import jieba.analyse
from multiprocessing import Pool
from bs4 import BeautifulSoup
def hianalyse(num):
cookie = cookielib.CookieJar()#对cookie进行声明
handler = urllib2.HTTPCookieProcessor(cookie)
opener = urllib2.build_opener(handler)
loginURL = 'http://www.hi-pda.com/forum/logging.php?action=login'
postdata = {
'formhash' : '7fb05e5b',
'referer' : 'index.php',
'loginfield' : 'username',
'username' : 'xxxx',
'password' : 'xxxxxxxx',
'questionid' : '0',
'answer' : '',
'loginsubmit' : 'true',
'cookietime' : '2592000'}
postdata = urllib.urlencode(postdata)
opener.open(loginURL,postdata)#用opener方式打开的网址就都是带cookie了

2.登陆并获取cookie就要开始分析网页源码了

1
http://www.hi-pda.com/forum/forumdisplay.php?fid=2&page=2

看的出来page后面的就是页数。

1
2
3
4
<th class="subject new">
<label>&nbsp;</label>
<span id="thread_1685642"><a href="viewthread.php?tid=1685642&amp;extra=page%3D2">这绝逼是假的,有人配音的。</a></span>
</th>

以viewthread.php?tid=任意数字&extra=page%3D2作为href标签的属性就可以准确定位,于是可以构造表达式

1
viewthread\.php\?tid=\d*&amp;extra=page%3D2

但是我这样构造缺找不到,所以还是老老实实的用viewthread来进行匹配,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
msg = ''#用来储存所有标题
for page_num in range(num*100-99, num*100):#url范围为1-100页
bsURL = 'http://www.hi-pda.com/forum/forumdisplay.php?fid=2&page='+str(page_num)#url结构
response = opener.open(bsURL)
page = BeautifulSoup(response)
tag = page.find_all(href = re.compile('viewthread\.php\?tid=\d*'))
for each_tag in tag:
if is_num_by_except(each_tag.get_text()) == True:
continue
else:
each_tag = each_tag.get_text().encode('utf-8')
msg = msg + each_tag

但是这样会遇到一个问题,就是有时候页码也会被匹配出来,这时候就需要一个函数来判断是否为纯数字

1
2
3
4
5
6
7
def is_num_by_except(num):
try:
int(num)#强制转换为数字类型
return True
except ValueError:
# print "%s ValueError" % num
return False

这样获取标题的部分就算结束了

3.多进程提高抓取效率
一开始是想用多线程方法的,后来发现自己对进程和线程的定义理解错了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
2.关系
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
相对进程而言,线程是一个更加接近于执行体的概念,它可以与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
3.区别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
1) 简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
2) 线程的划分尺度小于进程,使得多线程程序的并发性高。
3) 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
4) 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
5) 从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。
4.优缺点
线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移.

貌似大概的意思就是线程是一件事多个步骤操作,而进程则是多次完成多件事情。其实最重要的原因是threading模块没有看懂啦。

1
2
3
4
5
6
7
if __name__ == '__main__':
p = Pool()#这里括号里面如果有参数就是同时进行参数个任务,如果没有就是进行cpu的核心数个任务
for i in range(10):
p.apply_async(hianalyse,args=(i,))#这里是用来添加进程的
p.close()
p.join()

4.对抓取结果进行词频分析
这里中文分词建议使用mmseg,因为速度快。关键词分析则用jieba,因为方便。

1
2
pip install mmseg
pip install jieba

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#coding=utf-8
from mmseg import seg_txt
import jieba.analyse
f = open('temp.txt','r')#保存标题的文件
f_out = open('temp_out.txt','a+')
for i in seg_txt(f.read()):#用mmseg对其进行分词处理,得到的是个列表
f_out.write(i+'\n')
f.close()
f_out.close()
dic={}
for i in open('temp_out.txt'):#这是网上找来的一个词频统计脚本
array=[]
i=i.strip()
array=i.split()
for j in array:
if not dic.has_key(j):
dic[j]=0
dic[j]+=1
f=open('temp_out_out','w')
for i in dic.keys():
f.write (i+'\t'+str(dic[i])+'\n')
f.close()

如果使用jieba进行关键词提取,只需要一句

1
the_keyword=jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())

sentence是分析对象,topK是出现频率最高的前x个词,withWeight是是否需要返回词频,allowPOS是提取的词性。
这个语句返回的同样是个列表,直接用循环就可以全部输出

1
2
for wd, weight in the_keyword:
print wd, weight#输出关键词和他的词频(前提是withWeight=True)

最后分下一下我对hipda的discovery板块前1000页关键词提取的结果吧
此处输入图片的描述

p.s:
结巴github地址
multiprocessing模块用法