#简介
在每次论文被拒再投的过程中,都需要查询最近的与自己论文相关的会议列表。每到这种情况,我一遍采用的是遍历会伴www.myhuiban.com的网站,然后逐个查看会议,关注的有三点,投稿日期,ccf类别,会议相关内容。
##TODO: 需要加网站的截图,更清晰的说明为什么会有这个需求
思考下,也许自己可以写一个简单的python爬虫程序,将所有的会议列表下载下来,然后在本地建立一个所有会议的索引, 这样就可以个性化的定义搜索了。
昨天下午到今天中午,写了大概400行的python代码,基本完成需求。遇到的主要问题有模拟网站登录,正则表达式搜索, json的编码和解码,文件的读取与写入, 命令行参数相关。
#整体框架
Cookie模块: 负责模拟用户登录并保存cookie以便于下次使用
爬虫模块: 首先爬取会议的第一页的所有会议,并解析下一页的网址,然后逐个爬取下一页的会议列表,对每一个会议,根据其网址爬取其会议的详细信息,并保存到内存字典以及文件中
Json转换模块: 负责将会议字典对象转换为字符串并保存到文件,以及从文件中加载字典创建会议列表
搜索模块: 构造命令行参数,遍历会议进行模式匹配。
#具体模块
##Cookie模块
待爬虫的网址需要用户登录后才可以正常访问会议列表信息,因此需要手动模拟用户登录,并保存cookie,以便于下次访问直接使用cookie访问,而不需要再次登录了。
模拟登录并保存cookie的代码片段
def requestCookie(self):
#声明一个MozillaCookieJar对象实例来保存cookie,之后写入文件
self.cookie = cookielib.MozillaCookieJar(self.filename)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie))
postdata = urllib.urlencode({
'LoginForm[email]':'xxxxxxx',
'LoginForm[password]':'xxxxxx',
'LoginForm[rememberMe]':'0',
'LoginForm[rememberMe]':'1',
'yt0':'登录'
})
loginUrl = 'http://www.myhuiban.com/login'
#模拟登录,并把cookie保存到变量
result = opener.open(loginUrl,postdata)
#保存cookie到cookie.txt中
self.cookie.save(ignore_discard=True, ignore_expires=True)
上述代码首先创建了MozillaCookie的对象,然后创建了opener,利用它打开连接,它将通过POST请求将用户名和密码发送给服务器。
实用tips:
也许你可能需要爬取其他的需要登录的网页, 它需要POST的数据格式可能就会有变化,如何处理呢? 第一,利用浏览器的自带的开发者工具查看当登录时候POST的数据是什么, 第二,手动构造postdata,利用上面的python代码发起登录请求, 第三,对比浏览器返回的Cookie值与手动模拟登录的请求的Cookie值是否相同。
从文件中直接载入Cookie代码
self.cookie = cookielib.MozillaCookieJar()
self.cookie.load(self.filename, ignore_discard=True, ignore_expires=True)
for item in self.cookie:
print 'LoadCookie: Name = '+item.name
print 'LoadCookie:Value = '+item.value
通过打印对比一下是否和存储的一致。
Cookie文件加载和网络加载合并
通过以下的代码首先从文件中载入,如果载入不到就从网络中请求,请求完毕后保存到文件。通过这种方式,相当于建立了一个缓存机制,不需要每次都从网路中读取Cookie了。
def getCookie(self):
if(self.cookie == None):
self.loadCookie()
if(self.cookie == None):
self.requestCookie()
return self.cookie
##会议对象
将所有会议保存到会议对象中,需要定义会议对象。根据网页上会议的相关属性,定义如下的会议对象:
class Conference:
#注意jsonDecoder这个函数的名字必须完全一致,传入的参数名字也必须一致
def __init__(self, ccf, core, qualis, simple, traditinal, delay, sub, note, conf, place, num, browser, content, rate, id):
self.ccf = ccf
self.core = core
self.qualis = qualis
self.simple = simple
self.traditinal = traditinal
self.delay = delay
self.sub = sub
self.note = note
self.conf = conf
self.place = place
self.num = num
self.browser = browser
self.content = content
self.id = id
self.rate = rate
def setContent(self, content):
self.content = content
def setAcceptRate(self, rate):
self.rate = rate
def printConf(self):
print 'CCF CORE QUALIS ShortN Long Delay SubmissionDt Notification Conference Place NumberedHold Nread'
#print('x=%s, y=%s, z=%s' % (x, y, z))
print self.ccf, self.core , self.qualis , self.simple , self.traditinal , self.delay , self.sub , self.note , self.conf , self.place , self.num , self.browser
def printDetailConf(self):
self.printConf()
print('Content:')
print self.content
def isValid(self):
return self.id == -1
def json(self):
pass
@staticmethod
def createConf(line):
#u'<td></td><td>c</td><td>b2</td><td>IDEAL</td><td><a target="_blank" href="/conference/535">International Conference on Intelligent Data Engineering and Automated Learning</a></td><td></td><td>2016-05-15</td><td>2016-06-15</td><td>2016-10-12</td><td>Wroclaw, Poland</td><td>17</td><td>3932</td>'
#CCF CORE QUALIS 简称 全称 延期 截稿日期 通知日期 会议日期 会议地点 届数 浏览
pattern = r'<td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td><a target="_blank" href="(.*?)">(.*)</a></td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td><td>(.*?)</td>'
info = re.findall(pattern, line, re.S)[0]
conf = Conference()
conf.ccf = info[0]
conf.core = info[1]
conf.qualis = info[2]
conf.simple = info[3]
conf.id = info[4]
conf.traditinal = info[5]
conf.delay = info[6]
conf.sub = info[7]
conf.note = info[8]
conf.conf = info[9]
conf.place = info[10]
conf.num = info[11]
conf.browser = info[12]
#conf.printConf()
return conf
此会议对象接收一段html代码,并进行解析,将相应的属性解析出来。
##json相关
考虑到不能每次使用此程序都需要爬取所有的会议列表,因此需要将会议对象转换为字符串保存到文件中。 常用的对象序列化方法之一就是json
于是借用网络上的一份对象和json串的转换代码如下:
特此声明:下面的转换代码非本人所写,copy于网络,链接地址为:http://www.cnblogs.com/coser/archive/2011/12/14/2287739.html
class MyEncoder(json.JSONEncoder):
def default(self,obj):
#convert object to a dict
d = {}
d['__class__'] = obj.__class__.__name__
d['__module__'] = obj.__module__
d.update(obj.__dict__)
return d
class MyDecoder(js