简单的说,Scrapy爬虫框架会利用异步机制帮助提高网络爬虫的爬取速度。
最重要的,爬虫记载爬取失败的url,进行重复爬取,直到爬取失败的url列表为空时结束爬取,这显然提高数据的爬取质量。
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它占用资源非常的低,操作简单,适合用于存储爬虫结果数据。
多线程就像同时执行多个程序,多线程运行有如下优点:
class SQLiteWraper(object):
"""
数据库的一个小封装,更好的处理多线程写入
"""
def __init__(self,path,command='',*args,**kwargs):
self.lock = threading.RLock() #锁
self.path = path #数据库连接参数
if command!='':
conn=self.get_conn()
cu=conn.cursor()
cu.execute(command)
def get_conn(self):
conn = sqlite3.connect(self.path)#,check_same_thread=False)
conn.text_factory=str
return conn
def conn_close(self,conn=None):
conn.close()
def conn_trans(func):
def connection(self,*args,**kwargs):
self.lock.acquire()
conn = self.get_conn()
kwargs['conn'] = conn
rs = func(self,*args,**kwargs)
self.conn_close(conn)
self.lock.release()
return rs
return connection
@conn_trans
def execute(self,command,method_flag=0,conn=None):
cu = conn.cursor()
try:
if not method_flag:
cu.execute(command)
else:
cu.execute(command[0],command[1])
conn.commit()
except sqlite3.IntegrityError as e:
#print(e)
return -1
except Exception as e:
print(e)
return -2
return 0
@conn_trans
def fetchall(self,command="select name from xiaoqu",conn=None):
cu=conn.cursor()
lists=[]
try:
cu.execute(command)
lists=cu.fetchall()
except Exception as e:
print(e)
pass
return lists
利用数组生成数据库插入命令
def gen_xiaoqu_insert_command(info_dict):
"""
生成小区数据库插入命令
"""
info_list=[u'小区ID',u'小区名称',u'参考均价',u'大区域',u'小区域',u'建筑年代',u'建筑类型',u'物业费用',u'物业公司',u'开发商',u'楼栋总数',u'房屋总数',u'附近门店']
t=[]
for il in info_list:
if il in info_dict:
t.append(info_dict[il])
else:
t.append('')
t=tuple(t)
command=(r"insert into xiaoqu values(?,?,?,?,?,?,?,?,?,?,?,?,?)",t)
return command
def xiaoqu_spider(db_xq,url_page=u"http://sz.lianjia.com/xiaoqu/pg1rs%E6%98%8C%E5%B9%B3/"):
"""
爬取页面链接中的小区信息
"""
try:
res=requests.get(url_page,headers=hds[random.randint(0,len(hds)-1)])
plain_text=res.text
soup = BeautifulSoup(plain_text,"html.parser")
except (urllib.request.HTTPError, urllib.request.URLError) as e:
print(e)
exit(-1)
except Exception as e:
print(e)
exit(-1)
xiaoqu_list=soup.findAll('li',{'class':'clear xiaoquListItem'})
for xq in xiaoqu_list:
info_dict={}
info_dict.update({u'小区ID':xq.get('data-id')})
info_dict.update({u'小区名称':xq.find('div',{'class':'title'}).get_text()})
info_dict.update({u'参考均价':xq.find('div',{'class':'totalPrice'}).get_text()})
info_dict.update({u'大区域':xq.find('a',{'class':'district'}).get_text()})
info_dict.update({u'小区域':xq.find('a',{'class':'bizcircle'}).get_text()})
url_detail="https://sz.lianjia.com/xiaoqu/"+xq.get('data-id')+"/"
info=xiaoqu_spider_detail(url_detail)
try:
info_dict.update({u'建筑年代':info[0]})
info_dict.update({u'建筑类型':info[1]})
info_dict.update({u'物业费用':info[2]})
info_dict.update({u'物业公司':info[3]})
info_dict.update({u'开发商':info[4]})
info_dict.update({u'楼栋总数':info[5]})
info_dict.update({u'房屋总数':info[6]})
info_dict.update({u'附近门店':info[7]})
except Exception as e:
print(url_detail)
print(e)
command=gen_xiaoqu_insert_command(info_dict)
db_xq.execute(command,1)
def do_xiaoqu_spider(db_xq,region=u"futianqu"):
"""
爬取大区域中的所有小区信息
"""
url=u"http://sz.lianjia.com/xiaoqu/"+quote(region_pinyin)+"/"
try:
res=requests.get(url,headers=hds[random.randint(0,len(hds)-1)])
plain_text=res.text
soup = BeautifulSoup(plain_text,"html.parser")
except (urllib.request.HTTPError, urllib.request.URLError) as e:
print(e)
return
except Exception as e:
print(e)
return
d=json.loads(soup.find('div',{'class':'page-box house-lst-page-box'}).get('page-data'))
total_pages=d['totalPage']
threads=[]
for i in range(total_pages):
url_page=u"http://sz.lianjia.com/xiaoqu/"+quote(region_pinyin)+"/"+"pg%s/" % (i+1)
t=threading.Thread(target=xiaoqu_spider,args=(db_xq,url_page))
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join()
print(u"爬下了 %s 区全部的小区信息" % region)
构建函数调用百度地图API,查询poi点位置信息,获取位置标记
def getlocation(name):#调用百度API查询位置
bdurl='http://api.map.baidu.com/place/v2/search?query='
output='json'
ak='yPNB0qKB6sIVVupOWyKnzoxabwsSuK9M'#输入你刚才申请的密匙
region='深圳'
tag='房地产'
uri=bdurl+name+'&tag='+tag+'®ion='+region+'&output='+output+'&ak='+ak
res=requests.get(uri)
s=json.loads(res.text)['results']
if s==[]:
loc={'lng':'NULL','lat':'NULL'}
else:
s=json.loads(res.text)['results'][0]
loc=s.get('location', 'not exist')
if loc=="not exist":
loc={'lng':'NULL','lat':'NULL'}
return(loc)
完整代码请参考个人博客-资源下载。