从互联网上采集数据,最令人头痛的就是从海量个性化网站上去采集某一类数据(比如公司简介、产品信息等),因为每个网站的结构各不相同,所以采用传统的通过xpath、标签名称等定位采集数据的方法是比较困难的,下面是我针对公司简介采集编写的采集器,仅供参考。
采集的思想是:首先定位公司简介url,然后通过解析简介网页,提取公司简介数据。具体方法如下(下面配有代码):
# 采集公司简介网页的url:
第一步:对公司主页解析并扫描是否有关简介的固定标志比如,u'公司简介', u'集团简介',u'集团介绍',u'关于我们', u'公司介绍', u'企业简介',u'企业介绍',u'我们是谁'等;如果发现该标志,向前搜索1-2行解析文本,如果发现‘href’开头的信息,那么基本就是公司简介页面的url,返回url并退出函数。
第二步:如果第一步中没有发现简介固定标志或发现固定标志但没有找到href,说明有两种情况:一,简介就在主页上,直接退出函数。二、简介不是固定标志,而是类似‘关于微软’等这类和公司名称有关的简介个性标志,这种情况我们将扫描搜索包含个性标志词根比如,u'简介',u'关于',u'走进'的文本;
去掉这些词根,和公司名称去比较,如果剩下的词都在公司名称里,那么基本就是公司简介的标志了,然后再使用第一步后面的方法找到公司简介url,返回url并退出函数。
# 采集简介文本数据的方法
1、公司简介特征词典建立方法:根据以前的收集的公司简介文本,进行分词,统计词频,选择词频较大的词作为公司特征词典。
2、根据前面获取的公司简介url,解析该网页,并采集所有文本数据(get_text方法),按照3条规则去判断哪些文本属于公司简介。判断规则如下:
r1: 每条文本长度在20个字符以上的,这条文本有可能是公司简介文本
r2:每条文本中包含特征词数量大于公司简介特征词字典总数的10%,这条文本可能是公司简介文本
r3:每条文本中包含特征词比例大于5%,这条文本可能是公司简介文本
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
from urllib import urlopen
import re
import HTMLParser as HP
import pyodbc as po
import pandas as pd
def about_url_refine(t):
print t
t=t.strip()
p2=re.compile(r'http.*')
p= re.compile(r'\.\./.*')
p1= re.compile(r'/.*')
url_total_tag=0
if p2.match(t) is not None:
url_total_tag=1
else:
if p.match(t) is not None:
t= t[3:len(t)]
else:
if p1.match(t) is not None:
t= t[1:len(t)]
hp= HP.HTMLParser()
t= hp.unescape(t)
return t,url_total_tag
def company_url_refine(company_url):
p= re.compile(r'http.*')
if p.search(company_url) is None:
company_url= 'http://'+company_url
if company_url[-1]=='/':
company_url=company_url[0:(len(company_url)-1)]
return company_url
def get_about_url(url,company_name):
url= company_url_refine(url)
about_url = ''
about_main_tag = 0
try:
html = urlopen(url)
except BaseException:
print 'Unable to access site!'
about_url='1'
else:
try:
bsobj = BeautifulSoup(html, "html.parser")
except BaseException:
print url+' do not reach!'
about_url = '1'
else:
text = bsobj.prettify()
ts = text.split('\n')
p = re.compile(r'href=".*"')
url_tag=0
wr = open('text_main.txt', 'w')
for i in ts:
try:
wr.write(i.encode('GB18030') + '\n')
except UnicodeEncodeError:
wr.write('UnicodeEncodeError \n')
for i in range(len(ts)):
for j in about_str:
if ts[i].find(j) >= 0:
about_main_tag=1
if ts[i - 1].find('href') >= 0:
t = p.search(ts[i - 1])
tt = t.group()
tt = tt.split('"')
u1,u2=about_url_refine(tt[1])
if (u1.find('javascript:')<0) & (len(u1)>2):
if u2==1:
about_url= u1
else:
about_url = url +'/'+u1
print ts[i]
print 'S1:'+about_url
url_tag=1
break
else:
if ts[i-2].find('href')>=0:
t = p.search(ts[i - 2])
tt = t.group()
tt = tt.split('"')
u1, u2 = about_url_refine(tt[1])
if (u1.find('javascript:') < 0) & (len(u1) > 2):
if u2 == 1:
about_url = u1
else:
about_url = url + '/' + u1
print ts[i]
print 'S1:' + about_url
url_tag = 1
break
if url_tag==1:
break
if url_tag==0:
t1=0
p3= re.compile(r'[|]+')
for i in range(len(ts)):
for k in about_str_init:
if ts[i].find(k)>=0:
print str(i)
print ts[i]
tmp= ts[i].replace(k,'')
tmp= tmp.strip()
if p3.search(tmp) is not None:
print str(p3.search(tmp).start())
tmp= tmp[0:p3.search(tmp).start()]
if tmp.find(u'\u4e28')>=0:
tmp= tmp.split(u'\u4e28')[0]
if tmp.find(u'\u2223')>=0:
tmp = tmp.split(u'\u2223')[0]
print tmp
for j in range(len(tmp)):
if company_name.find(tmp[j])>=0:
t1=t1+1
if (t1+1)>= len(tmp):
about_main_tag=1
if ts[i - 1].find('href') >= 0:
t = p.search(ts[i - 1])
tt = t.group()
tt = tt.split('"')
u1, u2 = about_url_refine(tt[1])
if u1.find('javascript:') < 0:
if u2 == 1:
about_url = u1
else:
about_url = url + '/' + u1
print 'S2:'+about_url
url_tag=1
break
else:
if ts[i - 2].find('href') >= 0:
t = p.search(ts[i - 2])
tt = t.group()
tt = tt.split('"')
u1, u2 = about_url_refine(tt[1])
if (u1.find('javascript:') < 0) & (len(u1) > 2):
if u2 == 1:
about_url = u1
else:
about_url = url + '/' + u1
print ts[i]
print 'S1:' + about_url
url_tag = 1
break
if url_tag==1:
break
return about_url,about_main_tag ### 返回参数说明:about_url--不为空表示找到公司简介的网页url,为空表示没有找到简介网页url
### about_main_tag--0表示没有找到公司简介的相关标志,1表示找到公司简介的相关标志
### 如果上述参数返回值为('',1)表示没有找到简介的网页url,但找到了简介的有关标志,说明简介可能在主页上。
def get_about_info(company_url,company_name,kws_dic,r1,r2,r3):
about_url,about_main_tag= get_about_url(company_url,company_name)
about_text = ''
if about_url=='1':
about_url='Unable to access homepage'
if (about_url=='') & (about_main_tag==0):
print 'Not find about-url and about-tag! '
about_url='Not find about-url and about-tag'
else:
if (about_url=='') & (about_main_tag==1):
print 'Company-About on homepage!'
about_text= search_about_info(company_url,kws_dic,r1,r2,r3)
about_url= company_url
else:
print 'Find about-url: ' + about_url
about_text= search_about_info(about_url, kws_dic,r1,r2,r3)
return about_text,about_url
def search_about_info(about_url,kws_dic,r1,r2,r3):
about_url= about_url.split('#')[0]
about_text = []
try:
html = urlopen(about_url)
except BaseException:
print 'Unable to access about_page!'
about_text='Unable to access about_page'
else:
try:
bsobj = BeautifulSoup(html, "html.parser")
except BaseException:
print ' Do not reach! '+ about_url
else:
dt = bsobj.find('body')
try:
about_text_tmp = dt.get_text()
except AttributeError:
print 'Not find about text!'
about_text='Not find about text'
else:
about_text_tmp = about_text_tmp.split('\n')
'''
wr = open('texts.txt', 'w')
for i in about_text_tmp:
try:
wr.write(i.encode('GB18030') + '\n')
except UnicodeEncodeError:
wr.write('UnicodeEncodeError \n')
'''
about_text_tmp = bsobj.get_text()
about_text_tmp = about_text_tmp.split('\n')
for t in about_text_tmp:
t=t.strip()
if len(t) >= r1:
kws_count = 0
for k in kws_dic:
if t.find(k) >= 0:
kws_count = kws_count + 1
print str(kws_count) + ';' + str(round(float(kws_count) / float(len(t)), 8)) + '------' + t
if (kws_count >= len(kws_dic) * r2) | (float(kws_count)/float(len(t))>=r3):
about_text.append(t.strip())
return about_text
def get_company_data_SQL(database, nums):
#con = po.connect("DSN=coms_SQL;UID=sa;PWD=yxxy")
con = po.connect("DSN=coms_info;UID=sa;PWD=0829")
con_s = con.cursor()
con_s.execute("select top "+str(nums)+" company, firm_web from "+database +" order by NEWID()")
company_list, url_list=[],[]
for t in con_s:
company_list.append(t[0].strip())
tmp= t[1].replace(u':',':')
tmp= tmp.replace(u'。','.')
url_list.append(tmp.strip())
company_pd= pd.DataFrame({'company_name':company_list, 'company_url':url_list})
company_pd.to_csv('company_data.csv', index=False, encoding='GB18030')
return company_pd
if __name__ == '__main__':
about_str = [u'公司简介', u'集团简介',u'集团介绍',u'关于我们', u'公司介绍', u'企业简介',u'企业介绍',u'我们是谁']
about_str_init = [u'简介',u'关于',u'走进']
r1= 20 ## Rule1: 每条文本长度在20个字符以上的,这条文本有可能是公司简介文本
r2= 0.1 ## Rule2:每条文本中包含特征词数量大于公司简介特征词字典总数的10%,这条文本可能是公司简介文本
r3= 0.05 ## Rule3:每条文本中包含特征词比例大于5%,这条文本可能是公司简介文本
about_kw = pd.read_csv('company_about_kw_dic.csv', encoding='GB18030')
kws_dic = []
for i in range(len(about_kw)):
kws_dic.append(about_kw['word'][i])
company_name = u'北京梦之墨科技有限公司'
company_url = 'www.dreamink.cn'
about_texts, url = get_about_info(company_url, company_name, kws_dic, r1, r2, r3)
print 'About-url:'+ url
print 'About-text:'
for t in about_texts:
print t