python爬虫(19)爬取论坛网站——网络上常见的gif动态图

来源:互联网 发布:英语视频翻译软件 编辑:程序博客网 时间:2024/05/01 15:10

写在前面的话~

有段时间没有写爬虫相关的文章了,今天抽时间把之前做的一个程序分享给大家。

经常逛A站和B站的人,肯定对一个节目不陌生《网络上常见的GIF动态图

今天就来分享一下,怎么通过爬虫自动的将这些个动作收藏到自己的电脑中(其实这个程序5月份就写好了,一直拖到现在才想起来将它分享出来)。

一.思路分析

按照爬虫的基本规律:
1.找到目标
2.抓取目标
3.处理目标内容,获取有用的信息

1.首先我们的目标是:http://gifcc.com/forum.php    即找动图就上 GIFFCC.COM


这个网站呢,是一个论坛式网站,里面分了几大类,反正试试各种动图。
我们的目标呢,就是找到这(收)些(藏)动(到)图(自)的(己)地(电)址(脑).

2.看一下各个模块的网址,看一下有什么规律

'http://gifcc.com/forum-37-1.html',#其他各种GIF动态图出处 
'http://gifcc.com/forum-38-1.html', #美女GIF动态图出处 
'http://gifcc.com/forum-47-1.html',#科幻奇幻电影GIF动态图出处
'http://gifcc.com/forum-48-1.html',#喜剧搞笑电影GIF动态图出处
'http://gifcc.com/forum-49-1.html',#动作冒险电影GIF动态图出处
'http://gifcc.com/forum-50-1.html'#恐怖惊悚电影GIF动态图出处
对的,没错,如果以游客身份访问,那么各个板块的网址就是这样的形式 http://gifcc.com/forum-XX -1.html
那么每个模块中的内容又有什么规律? 来直接上图:



我们关注的是当前页的网址,以及这个页码数,跳到第二页之后,地址变成:http://gifcc.com/forum-38-2.html
那么也就是说 网址的 规律就是 http://gifcc.com/forum-XX-XX.html
这里注意一点,网站的图片是动态加载的, 只有你往下滑动的时候,下面的图片才会逐渐的显现出来,这个暂且记下


3.每一张动图的所在页面的规律


其实这个没啥规律,但是只要我们找到单个图片的地址,就没啥难处理的了.

二 开工动手


1.获取入口页面内容
即根据传入的URL,获取整个页面的源码
#仅仅获取页面内容def get_html_Pages(self,url):  try:   #browser = webdriver.PhantomJS(executable_path=r'C:\Python27\Scripts\phantomjs.exe') browser = webdriver.PhantomJS() browser.get(url)html = browser.execute_script("return document.documentElement.outerHTML")browser.close()html=HTMLParser.HTMLParser().unescape(html).decode('utf-8')return html        #捕捉异常,防止程序直接死掉    except Exception,e:  print u"连接失败,错误原因",ereturn None   
这里我们使用了webdriver以及PhantomJS 这些模块,为什么呢?因为网页是动态加载的,这样可以抓取的数据全一点.
那这里还有个疑问, 为什么没有滑动啊什么的,得到的数据

2.获取页码数
#获取页码def get_page_num(self,html):doc = pq(html)  print u'开始获取总页码'#print doc('head')('title').text()#获取当前titletry:#如果当前页面太多,超过8页以上,就使用另一种方式获取页码if doc('div[class="pg"]')('[class="last"]'):num_content= doc('div[class="pg"]')('[class="last"]').attr('href')print  num_content.split('-')[1].split('.')[0]return num_content.split('-')[1].split('.')[0]else:num_content= doc('div[class="pg"]')('span')return filter(str.isdigit,str(num_content.text()))[0]#如果获取页码失败,那么就返回1, 即值获取1页内容except Exception,e:print u'获取页码失败'.ereturn '1'

这里的页码处理用到了一个模块pq, 即  PyQuery  
 from pyquery import PyQuery as pq 
采用PyQuery的方式查找我们需要的元素,感觉更好处理一点,挺方便的
同时这里的处理稍微有点意思,如果观察这个页面的话,会发现,每个模块的页码数,在上面和下面都有一个,然后我这里裁取的一下,因为我们只需要一个页码数字即可


3-6 第三步到第六步一起来说
其实就是根据页码数,来进行遍历,获取到每一页的内容
然后得到每一页中的所有图片地址

print  u'总共有 %d页内容' % int(page_num)#3.遍历每一页的内容for num in range(1,int(page_num)):#4.组装新的urlnew_url = self.url.replace( self.url.split('-')[2],(str(num)+'.html') )print u'即将获取的页面是:',new_url#5.加载每一页内容,获取gif list 的内容items=self.parse_items_by_html(self.get_all_page(new_url))print u'在第%d页,找到了%d 个图片内容' % (num,len(items))#6.处理每一个元素的内容self.get_items_url(items,num)
在进行获取每一页的内容的时候,需要重新组装页面地址。
#4.组装新的urlnew_url = self.url.replace( self.url.split('-')[2],(str(num)+'.html') )print u'即将获取的页面是:',new_url
有了新的地址,就可以获取当前页面的内容,并进行数据处理,得到每一张图片的地址列表

#5.加载每一页内容,获取gif list 的内容items=self.parse_items_by_html(self.get_all_page(new_url))print u'在第%d页,找到了%d 个图片内容' % (num,len(items))
#解析页面内容,获取gif的图片listdef parse_items_by_html(self, html):  doc = pq(html)  print u'开始查找内容msg'     return doc('div[class="c cl"]')
在获取到图片列表后,再次解析,获取每一张图片的URL
#解析gif 的list ,处理每一个gif内容def get_items_url(self,items,num):i=1for article in items.items():print u'开始处理数据(%d/%d)' % (i, len(items))#print articleself.get_single_item(article,i,num)i +=1#处理单个gif内容,获取其地址,gif 最终地址def get_single_item(self,article,num,page_num):gif_dict={}#每个页面的地址gif_url= 'http://gifcc.com/'+article('a').attr('href')#每个页面的标题gif_title= article('a').attr('title')#每张图的具体地址#html=self.get_html_Pages(gif_url)#gif_final_url=self.get_final_gif_url(html) gif_dict['num']=numgif_dict['page_num']=page_numgif_dict['gif_url']=gif_urlgif_dict['gif_title']=gif_titleself.gif_list.append(gif_dict)data=u'第'+str(page_num)+'页|\t'+str(num)+'|\t'+gif_title+'|\t'+gif_url+'\n'self.file_flag.write(data)
在这里,把数据整合一下,为将数据写入数据库做准备

7.将图片存到本地,以及将数据写入数据库

#使用urllib2来获取图片最终地址def get_final_gif_url_use_urllib2(self,url):try:html= urllib2.urlopen(url).read()gif_pattern=re.compile('<div align="center.*?<img id=.*?src="(.*?)" border.*?>',re.S)return re.search(gif_pattern,html).group(1)except Exception,e:print u'获取页面内容出错:',e#最终处理存贮数据def get_gif_url_and_save_gif(self):def save_gif(url,name):try:urllib.urlretrieve(url, name)except Exception,e:print '存贮失败,原因:',efor i in range(0,len(self.gif_list)):gif_dict=self.gif_list[i]gif_url=gif_dict['gif_url']gif_title=gif_dict['gif_title']#依然使用webdriver获取最终的gif地址final_html=self.get_html_Pages(gif_url)gif_final_url=self.get_final_gif_url(final_html)#使用另外一种方式(urllib2)获取最终地址#gif_final_url=self.get_final_gif_url_use_urllib2(gif_url)gif_dict['gif_final_url']=gif_final_urlprint u'开始向数据库写入第%d页第%d项数据,并开始存贮图片到本地 ' % (gif_dict['page_num'],gif_dict['num'])self.BookTable.insert_one(gif_dict)gif_name=self.dir_name+'/'+gif_title+'.gif'save_gif(gif_final_url,gif_name)
到这里其实大体的内容已经完成了.

我们能够将这个论坛各个模块的动图都存到本地,同时呢,也将数据放入到了数据库中

三 数据库的筛选

在完成了将数据放入到数据库的之后, 我想着可以直接通过调用数据库,将图片保存
(为什么有这个想法呢,因为我发现如果直接在主程序中存贮图片,它跑的太慢了,不如将数据都放到数据库中,之后专门调用数据库来贮存图片)
但是这里发现一个问题,数据中的内容挺多的,然后发现了好多内容是重复的,因此我们需要对数据库进行去重
关于数据去重的内容,其实我之前的文章已经写过了(写那篇文章的时候,这个爬虫已经完成了呢~)
主要思路是针对某一个元素的数量进行操作,pymongo里面有一个方法是可以统计指定元素的数量的,如果当前元素只有一个,就不管,不是一个元素,就删除
核心代码如下:

for url in collection.distinct('name'):#使用distinct方法,获取每一个独特的元素列表num= collection.count({"name":url})#统计每一个元素的数量print numfor i in range(1,num):#根据每一个元素的数量进行删除操作,当前元素只有一个就不再删除print 'delete %s %d times '% (url,i)#注意后面的参数, 很奇怪,在mongo命令行下,它为1时,是删除一个元素,这里却是为0时删除一个collection.remove({"name":url},0)for i in  collection.find({"name":url}):#打印当前所有元素print iprint collection.distinct('name')#再次打印一遍所要去重的元素

四 读取数据库中的内容,存贮图片

数据去重之后,再次进行图片的存贮,就方便多了
之后如果图片删除了,也不用重新跑一边,或者说有时候本地图片占地方,那么只用保存有数据库的数据就好了
核心代码如下:

def save_gif(url,name):try:urllib.urlretrieve(url, name)except Exception,e:print u'存贮失败,原因:',eclient = pymongo.MongoClient('localhost', 27017) print client.database_names()db = client.GifDBfor table in  db.collection_names():print 'table name is ',tablecollection=db[table]for item in  collection.find():try: if item['gif_final_url']:url,url_title= item['gif_final_url'],item['gif_title']gif_filename=table+'/'+url_title+'.gif'print 'start save %s, %s' % (url,gif_filename)save_gif(url,gif_filename)except Exception,e:print u'错误原因:',e

完整代码

01_get_gif_url.py
#coding: utf-8 from pyquery import PyQuery as pq  from selenium import webdriver import HTMLParser,urllib2,urllib,re,osimport pymongoimport timeimport sys  reload(sys)  sys.setdefaultencoding('utf-8')  class download_gif:def __init__(self):self.url='http://gifcc.com/forum-38-1.html'self.url_list=['http://gifcc.com/forum-37-1.html',#其他各种GIF动态图出处 'http://gifcc.com/forum-38-1.html', #美女GIF动态图出处 'http://gifcc.com/forum-47-1.html',#科幻奇幻电影GIF动态图出处'http://gifcc.com/forum-48-1.html',#喜剧搞笑电影GIF动态图出处'http://gifcc.com/forum-49-1.html',#动作冒险电影GIF动态图出处'http://gifcc.com/forum-50-1.html'#恐怖惊悚电影GIF动态图出处]self.choices={'1':u'其他各种GIF动态图出处','2':u'美女GIF动态图出处','3':u'科幻奇幻电影GIF动态图出处','4':u'喜剧搞笑电影GIF动态图出处','5':u'动作冒险电影GIF动态图出处','6':u'恐怖惊悚电影GIF动态图出处'}self.dir_name=u'gif出处'self.gif_list=[]self.connection = pymongo.MongoClient()  #BookTable.insert_one(dict_data)#插入单条数据  #BookTable.insert(dict_data)#插入 字典list 数据 #获取页面内容,并且加载JS, 通过滚动获取页面更多的元素def get_all_page(self,url):try:#browser = webdriver.PhantomJS(executable_path=r'C:\Python27\Scripts\phantomjs.exe') browser = webdriver.PhantomJS() browser.get(url)#time.sleep(3) #页面滚动js = "var q=document.body.scrollTop=100000"    #for i in range(5):  #调试语句,先暂时不加载太多次数for i in range(30):  #循环执行下滑页面50次  browser.execute_script(js)  #加载一次,休息一下  time.sleep(1)print u'这是第 %d 次划动页面' % i# 执行js得到整个页面内容html = browser.execute_script("return document.documentElement.outerHTML")browser.close()html=HTMLParser.HTMLParser().unescape(html)return htmlexcept Exception,e:print u'发生错误:',e#解析页面内容,获取gif的图片listdef parse_items_by_html(self, html):  doc = pq(html)  print u'开始查找内容msg'     return doc('div[class="c cl"]')#解析gif 的list ,处理每一个gif内容def get_items_url(self,items,num):i=1for article in items.items():print u'开始处理数据(%d/%d)' % (i, len(items))#print articleself.get_single_item(article,i,num)i +=1#处理单个gif内容,获取其地址,gif 最终地址def get_single_item(self,article,num,page_num):gif_dict={}#每个页面的地址gif_url= 'http://gifcc.com/'+article('a').attr('href')#每个页面的标题gif_title= article('a').attr('title')#每张图的具体地址#html=self.get_html_Pages(gif_url)#gif_final_url=self.get_final_gif_url(html) gif_dict['num']=numgif_dict['page_num']=page_numgif_dict['gif_url']=gif_urlgif_dict['gif_title']=gif_titleself.gif_list.append(gif_dict)data=u'第'+str(page_num)+'页|\t'+str(num)+'|\t'+gif_title+'|\t'+gif_url+'\n'self.file_flag.write(data)#通过webdriver获得页面内容后,获得最终地址def get_final_gif_url(self,html):doc = pq(html) image_content= doc('td[class="t_f"]')gif_url= image_content('img').attr('src')return gif_url#使用urllib2来获取图片最终地址def get_final_gif_url_use_urllib2(self,url):try:html= urllib2.urlopen(url).read()gif_pattern=re.compile('<div align="center.*?<img id=.*?src="(.*?)" border.*?>',re.S)return re.search(gif_pattern,html).group(1)except Exception,e:print u'获取页面内容出错:',e#最终处理存贮数据def get_gif_url_and_save_gif(self):def save_gif(url,name):try:urllib.urlretrieve(url, name)except Exception,e:print '存贮失败,原因:',efor i in range(0,len(self.gif_list)):gif_dict=self.gif_list[i]gif_url=gif_dict['gif_url']gif_title=gif_dict['gif_title']#依然使用webdriver获取最终的gif地址final_html=self.get_html_Pages(gif_url)gif_final_url=self.get_final_gif_url(final_html)#使用另外一种方式(urllib2)获取最终地址#gif_final_url=self.get_final_gif_url_use_urllib2(gif_url)gif_dict['gif_final_url']=gif_final_urlprint u'开始向数据库写入第%d页第%d项数据,并开始存贮图片到本地 ' % (gif_dict['page_num'],gif_dict['num'])self.BookTable.insert_one(gif_dict)gif_name=self.dir_name+'/'+gif_title+'.gif'save_gif(gif_final_url,gif_name)#仅仅获取页面内容def get_html_Pages(self,url):  try:   #browser = webdriver.PhantomJS(executable_path=r'C:\Python27\Scripts\phantomjs.exe') browser = webdriver.PhantomJS() browser.get(url)html = browser.execute_script("return document.documentElement.outerHTML")browser.close()html=HTMLParser.HTMLParser().unescape(html).decode('utf-8')return html        #捕捉异常,防止程序直接死掉    except Exception,e:  print u"连接失败,错误原因",ereturn None   #获取页码def get_page_num(self,html):doc = pq(html)  print u'开始获取总页码'#print doc('head')('title').text()#获取当前titletry:#如果当前页面太多,超过8页以上,就使用另一种方式获取页码if doc('div[class="pg"]')('[class="last"]'):num_content= doc('div[class="pg"]')('[class="last"]').attr('href')print  num_content.split('-')[1].split('.')[0]return num_content.split('-')[1].split('.')[0]else:num_content= doc('div[class="pg"]')('span')return filter(str.isdigit,str(num_content.text()))[0]#如果获取页码失败,那么就返回1, 即值获取1页内容except Exception,e:print u'获取页码失败'.ereturn '1'# filter(str.isdigit,num_content)#从字符串中提取数字#创建文件夹def mk_dir(self,path):if not os.path.exists(path):  os.makedirs(path) def set_db(self,tablename):self.BookDB = self.connection.GifDB         #数据库db的名字  self.BookTable =self.BookDB[tablename]           #数据库table表的名字  #主函数def run(self):choice_type=5if choice_type:#for choice_type in range(len(self.choices)): if  choice_type+1:self.dir_name=self.choices[str(choice_type+1)].strip()self.url=self.url_list[int(choice_type)]print self.dir_name,self.url#0.创建文件夹存贮图片,建立文件存贮内容self.mk_dir(self.dir_name)self.filename=self.dir_name+'/'+self.dir_name+'.txt'print self.filenameself.file_flag=open(self.filename,'w')self.set_db(self.dir_name)self.BookTable .insert({'filename':self.dir_name})print self.url#1.获取入口页面内容html=self.get_html_Pages(self.url)#2.获取页码数目page_num=self.get_page_num(html)print  u'总共有 %d页内容' % int(page_num)#3.遍历每一页的内容#page_num=3#调试语句,先暂时将页面内容设置的小一点for num in range(1,int(page_num)):#4.组装新的urlnew_url = self.url.replace( self.url.split('-')[2],(str(num)+'.html') )print u'即将获取的页面是:',new_url#5.加载每一页内容,获取gif list 的内容items=self.parse_items_by_html(self.get_all_page(new_url))print u'在第%d页,找到了%d 个图片内容' % (num,len(items))#6.处理每一个元素的内容self.get_items_url(items,num)#5.数据全部抓取完毕,开始处理数据self.get_gif_url_and_save_gif()print 'success'self.file_flag.close()if __name__ == '__main__':  print u'''            **************************************************              **    Welcome to Spider of  GIF 出处图片        **              **         Created on 2017-05-21                **              **         @author: Jimy _Fengqi                **              ************************************************** '''  print u''' 选择你要下载的gif图片类型1:'其他各种GIF动态图出处'2:'美女GIF动态图出处'3:'科幻奇幻电影GIF动态图出处'4:'喜剧搞笑电影GIF动态图出处'5:'动作冒险电影GIF动态图出处'6:'恐怖惊悚电影GIF动态图出处''''#选择要下载的类型mydownload=download_gif()html=mydownload.run()
02_delete_repeat_url_in_mongodb.py

#coding: utf-8 from pyquery import PyQuery as pq  from selenium import webdriver import HTMLParser,urllib2,urllib,re,osimport pymongoimport timeimport sys  reload(sys)  sys.setdefaultencoding('utf-8')  import pymongo  def save_gif(url,name):try:urllib.urlretrieve(url, name)except Exception,e:print '存贮失败,原因:',edef print_database_and_table_name():import pymongoclient = pymongo.MongoClient('localhost', 27017) print client.database_names()for database in client.database_names():for table in  client[database].collection_names():print 'table  [%s]  is in database [%s]' % (table,database)def delete_single_database_repeat_data():import pymongoclient = pymongo.MongoClient('localhost', 27017) db=client.GifDBtemptemp2#这里是将要清洗数据的数据库名字for table in  db.collection_names():print 'table name is ',tablecollection=db[table]for url in collection.distinct('gif_title'):#使用distinct方法,获取每一个独特的元素列表num= collection.count({"gif_title":url})#统计每一个元素的数量print numfor i in range(1,num):#根据每一个元素的数量进行删除操作,当前元素只有一个就不再删除print 'delete %s %d times '% (url,i)#注意后面的参数, 很奇怪,在mongo命令行下,它为1时,是删除一个元素,这里却是为0时删除一个collection.remove({"gif_title":url},0)for i in  collection.find({"gif_title":url}):#打印当前所有元素print idef delete_repeat_data():import pymongoclient = pymongo.MongoClient('localhost', 27017) db = client.localcollection = db.personfor url in collection.distinct('name'):#使用distinct方法,获取每一个独特的元素列表num= collection.count({"name":url})#统计每一个元素的数量print numfor i in range(1,num):#根据每一个元素的数量进行删除操作,当前元素只有一个就不再删除print 'delete %s %d times '% (url,i)#注意后面的参数, 很奇怪,在mongo命令行下,它为1时,是删除一个元素,这里却是为0时删除一个collection.remove({"name":url},0)for i in  collection.find({"name":url}):#打印当前所有元素print iprint collection.distinct('name')#再次打印一遍所要去重的元素delete_single_database_repeat_data()

03_from_mongodb_save_pic.py

#coding: utf-8 from pyquery import PyQuery as pq  from selenium import webdriver import HTMLParser,urllib2,urllib,re,osimport pymongoimport timeimport sys  reload(sys)  sys.setdefaultencoding('utf-8')  import pymongo  def save_gif(url,name):try:urllib.urlretrieve(url, name)except Exception,e:print u'存贮失败,原因:',eclient = pymongo.MongoClient('localhost', 27017) print client.database_names()db = client.GifDBfor table in  db.collection_names():print 'table name is ',tablecollection=db[table]for item in  collection.find():try: if item['gif_final_url']:url,url_title= item['gif_final_url'],item['gif_title']gif_filename=table+'/'+url_title+'.gif'print 'start save %s, %s' % (url,gif_filename)save_gif(url,gif_filename)except Exception,e:print u'错误原因:',e
Github地址:https://github.com/JimyFengqi/Gif_Spider

如果感觉博主的内容有帮助,可以支持一下

阅读全文
1 0
原创粉丝点击