heartsong/scrapy.cfg文件
#由scrapy startproject自动创建 # #有关[部署]部分的更多信息,请参阅: #https ://scrapyd.readthedocs.org/en/latest/deploy.html [设置] 默认 = heartsong.settings [部署] # URL = HTTP://本地主机:6800 / project = heartsong
heartsong/heartsong/items.py文件
# - * - coding:utf-8 - * - import scrapy class HeartsongItem(scrapy。项): title = scrapy.Field()#帖子 的标题 url = scrapy.Field()#帖子 的网页链接 author = scrapy.Field()#帖子 的作者 post_time = scrapy.Field() #发表时间 content = scrapy.Field()#帖子 的内容
heartsong/heartsong/pipelines.py文件
# - * - coding:utf-8 - * - class HeartsongPipeline(object): def process_item(self,item,spider): file = open(“ items.txt ”,“ a ”) #以追加的方式打开文件,不存在则创建 #因为项目中的数据是unicode的编码,为了在控制台中查看数据的有效性和保存, #将其编码改为UTF-8 item_string = str(item).decode(“ unicode_escape ”).encode(' utf-8 ') file .write(item_string) file .write(' \ n ') 文件 .close() print item_string #在控制台输出 return item #会在控制台输出原料数据,可以选择不写
heartsong/heartsong/settings.py文件
# - * - coding:utf-8 - * - BOT_NAME = ' heartsong ' SPIDER_MODULES = [ ' heartsong.spiders ' ] NEWSPIDER_MODULE = ' heartsong.spiders ' ROBOTSTXT_OBEY = False #不遵守Robot协议 #配置管道,数字代表优先级,因为本项目只有一个管道,所以可取1-1000中的任意值 ITEM_PIPELINES = { ' heartsong.pipelines.HeartsongPipeline ': 300, }
heartsong/heartsong/spiders/heartsong_scrapy.py文件
# - * - coding:utf-8 - * - #进口scrapy#可以用这句代替下面三句,但不推荐 from scrapy.spiders import spiders
from scrapy.selector import Selector [from scrapy] import request from heartsong.items import HeartsongItem #如果报错是pyCharm对目录理解错误的原因,不影响 class HeartsongSpider(spiders): name = “ heartsong ” allowed_domains = [ “ heartsong.top ” ] #允许爬取的域名,非此域名的网页不会取取 start_urls = [ #起始URL,这里设置为从最大TID开始,向0的方向迭代 “ http://www.heartsong.top/forum.php?mod=viewthread&tid=34 ” ] #用来保持登录状态,可把铬上拷贝下来的字符串形式的cookie转化成字典形式,粘贴到此处 cookies = {} #发送给服务器的HTTP头信息,有的网站需要伪装出浏览器头进行爬取,有的则不需要 头= { # '连线':'保持活力', ' User-Agent ': ' Mozilla / 5.0(X11; Linux x86_64)AppleWebKit / 537.36(KHTML,如Gecko)Chrome / 52.0.2743.82 Safari / 537.36 ' } #对请求的返回进行处理的配置 meta = { ' dont_redirect ': True, #禁止网页重定向 ' handle_httpstatus_list ':[ 301, 302 ] #对哪些异常返回进行处理 } def get_next_url(self,oldUrl): “”” 说明:返回下次迭代的网址 :param oldUrl:上一个爬去过的url :return:下次要爬取的url “”” #传入的URL格式:HTTP://www.heartsong.top/forum.php MOD = viewthread&TID = 34 l = oldUrl.split(' = ') #用等号分割字符串 oldID = int(l [ 2 ]) newID = oldID - 1 if newID == 0: #如果tid迭代到0了,说明网站爬完,爬虫可以结束了 返回 newUrl = l [ 0 ] + “ = ” + l [ 1 ] + “ = ” + str(newID) #构造出新的url return str(newUrl) #返回新的url def start_requests(self): “”” 这是一个重载函数,它的作用是发出第一个请求请求 :返回: “”” #带着头,cookie去请求self.start_urls [0],返回的响应会被送到 #回调函数解析中 yield Request(self .start_urls [ 0 ], callback = self .parse,headers = self .headers, cookies = self .cookies,meta = self .meta) def parse(self,response): “”” 用以处理主题贴的首页 :参数响应: :返回: “”” 选择器=选择器(响应) #创建选择器 table = selector.xpath(' // * [starts-with(@id,“pid”)] ') #取出所有的楼层 如果 没有表格: #这个链接内没有一个楼层,说明此主题贴可能被删了, #把这类网址保存到一个文件里,以便审查原因 打印 “不良网址!” f = 开放(' badurl.txt ',' a ') f.write(response.url) f.write(' \ n ') f.close() #发起下一个主题贴的请求 next_url = self .get_next_url(response.url) # response.url就是原请求的url 如果 next_url != None: #如果返回了新的url yield请求(next_url,callback = self .parse,headers = self .headers, cookies = self .cookies,meta = self .meta) 返回 对于每一个在表: item = HeartsongItem() #实例化一个item #因为后来我在论坛里删除了大量的机器回帖,所以有的楼层里没有作者信息 尝试: #通过XPath的匹配信息,注意提取物()方法返回的是一个列表 item [ ' author ' ] = each.xpath(' tr [1] / td [@ class =“pls”] / div [@ class =“pls favatar”] / div [@ class =“pi”] / div [ @ class =“authi”] / a / text()').extract()[ 0 ] item [ ' post_time ' ] = each.xpath(' tr [1] / td [@ class =“plc”] / div [@ class =“pi”] ').re(r ' [ 0-9 ] + - [ 0-9 ] + - [ 0-9 ] + [ 0-9 ] +:[ 0-9 ] +:[ 0-9 ] + ')[ 0 ] 除了: 继续 #的XPath的字符串(。)用法,解决标签套标签的情况,具体解释请自行找的XPath教程 content_list = each.xpath(' .// td [ @class = " t_f“] ').xpath(' string(。)').extract() content = “ ”. join(content_list) #将列表转化为字符串 item [ ' url ' ] = response.url #用这种方式获取网页的网址 #把内容中的换行符,空格等去掉 item [ ' content ' ] = content.replace(' \ r \ n ',' ').replace(' ',' ').replace(' \ n ',' ') yield item #将创建并赋值好的Item对象传递到PipeLine当前进行处理 pages = selector.xpath(' // * [@ id =“pgt”] / div / div / label / span ') 如果页面: #如果页面不是空列表,说明该主题帖分页 pages = pages [ 0 ] .re(r ' [ 0-9 ] + ')[ 0 ] #正则匹配出总页数 打印 “这篇文章有”,页面,“页面” # response.url格式:http://www.heartsong.top/forum.php?mod=viewthread&tid=34 #子utl格式:http://www.heartsong.top/forum.php?mod=viewthread&tid=34&page=1 tmp = response.url.split(' = ') #以下 =分割网址 #循环生成所有子页面的请求 用于 PAGE_NUM 在 x范围(2,INT(页)+ 1): #构造新的网址 sub_url = tmp [ 0 ] + ' = ' + tmp [ 1 ] + ' = ' + tmp [ 2 ] + ' page = ' + str(page_num) #注意此处的回调函数是self.sub_parse,就是说这个请求的响应会传到 # self.sub_parse里去处理 yield Request(sub_url,callback = self .sub_parse,headers = self .headers, cookies = self .cookies,meta = self .meta) #发起下一个主题贴的请求 next_url = self .get_next_url(response.url) # response.url就是原请求的url 如果 next_url != None: #如果返回了新的url yield请求(next_url,callback = self .parse,headers = self .headers, cookies = self .cookies,meta = self .meta) def sub_parse(self,response): “”” 用以爬取主题贴除首页外的其他子页 :参数响应: :返回: “”” 选择器=选择器(响应) table = selector.xpath(' // * [starts-with(@id,“pid”)] ') #取出所有的楼层 对于每一个在表: item = HeartsongItem() #实例化一个item 尝试: #通过XPath的匹配信息,注意提取物()方法返回的是一个列表 item [ ' author ' ] = each.xpath(' tr [1] / td [@ class =“pls”] / div [@ class =“pls favatar”] / div [@ class =“pi”] / div [ @ class =“authi”] / a / text()').extract()[ 0 ] item [ ' post_time ' ] = each.xpath(' tr [1] / td [@ class =“plc”] / div [@ class =“pi”] ').re(r ' [ 0-9 ] + - [ 0-9 ] + - [ 0-9 ] + [ 0-9 ] +:[ 0-9 ] +:[ 0-9 ] + ')[ 0 ] 除了: 继续 content_list = each.xpath(' .// td [ @class = " t_f“] ').xpath(' string(。)').extract() content = “ ”. join(content_list) #将列表转化为字符串 item [ ' url ' ] = response.url #用这种方式获取网页的网址 #把内容中的换行符,空格等去掉 item [ ' content ' ] = content.replace(' \ r \ n ',' ').replace(' ',' ').replace(' \ n ',' ') yield item #将创建并赋值好的Item对象传递到PipeLine当前进行处理