爬虫日记---七日热点scrapy版

受大牛们的鼓励,继2个熬夜的晚上终于做完scrapy版的“七日热点”。宝宝好累,做到凌晨,电脑差一点被收走。 赶紧开始记录。

主要参考文章:

Scrapy 0.24 文档
Scrapy爬取"单页面"数据(一)
Scrapy爬取多层网页结构数据(二)
Scrapy抓取多层网页结构详解(三)
爬虫小分队二组Scrapy框架收录专题-20170423(二)

Scrapy 是专门用来爬取网站数据的应用框架。不能直接用pycharm来创建一个scrapy的project。需要现在shell中写入scrapy startproject 项目名称。然后打开pycharm,就会生成类似于如下多个py文件组成项目。

项目名称/
    scrapy.cfg
    tutorial/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

具体每个py文件的功能可以查找相关资料。现在需要做的是在spiders目录下新建一个你的爬虫主的py文件。这就是你要写爬虫的主要地方。

代码如下组成

1、items.py

存储爬取数据。 其类型类似于词典。用于声明可用字段的简单语法。

from scrapy import Item,Field

class SevendayItem(Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    user=Field() #作者
    title=Field() #标题
    read_qty=Field() #阅读量
    commend_qty=Field() #评论数量
    admire_qty=Field() #喜欢数量
    reward=Field() #打赏
    topic=Field() #被收入专题

2、settings.py

设置CSV文件存储位置和本机的user_agent

USER_AGENT='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36'
FEED_URI=u'sevenday.csv'
FEED_FORMAT='CSV'

3、main.py

启动爬虫

#-*- coding:utf-8 -*-
from scrapy import cmdline
cmdline.execute("scrapy crawl sevenday1".split())

4、sevenday.py

#-*- coding:utf-8 -*-
import sys
sys.path.append('..')
from scrapy.spiders import CrawlSpider
from scrapy.http import Request
from items import SevendayItem
from scrapy.selector import Selector
import sys
import re
import json

reload(sys)
sys.setdefaultencoding('utf-8')

class sevenday(CrawlSpider):
    name='sevenday1'
    start_urls=['http://www.jianshu.com/trending/weekly?utm_medium=index-banner-s&utm_source=desktop&page=1']

    def parse(self, response):
        selector=Selector(response)
        datas=selector.xpath('//ul[@class="note-list"]/li')
        for data in datas:
            base_url = data.xpath('div/a/@href')
            if base_url:
                detail_url='http://www.jianshu.com'+data.xpath('div/a/@href').extract()[0]
                print 'ddd',detail_url
                yield Request(detail_url,callback=self.parse_item)
        urls = ['http://www.jianshu.com/trending/weekly?utm_medium=index-banner-s&utm_source=desktop&page={}'.format(i) for i in range(2, 9)]
        for newurl in urls:
            yield Request(newurl, callback=self.parse)

    def parse_item(self, response):
        #items=[]
        item=SevendayItem()
        selector=Selector(response)
        user=selector.xpath('//span[@class="name"]/a/text()').extract()[0]
        title=selector.xpath('//div[@class="article"]/h1[@class="title"]/text()').extract()[0]
        read_qty=re.findall('"views_count":(.*?),', response.text, re.S)[0]
        comment_qty = re.findall('"comments_count":(.*?),', response.text, re.S)[0]
        admire_qty=re.findall('"likes_count":(.*?),', response.text, re.S)[0]
        id = re.findall('"id":(.*?),', response.text, re.S)[0]
        reward_url = ['http://www.jianshu.com/notes/{}/rewards.json'.format(str(id))]
        print reward_url[0]
        item['user']=user
        item['title']=title
        item['read_qty']=read_qty
        item['commend_qty']=comment_qty
        item['admire_qty']=admire_qty
        #items.append(item)
        #yield Request(reward_url[0],meta={'id':id,'user':user,'title':title,'read_qty':read_qty,'comment_qty':comment_qty,'admire_qty':admire_qty},callback=self.parse_info)
        yield Request(reward_url[0],meta={'id':id,'item':item},callback=self.parse_info)

    def parse_info(self,response):
        selector=Selector(response)
        item1=response.meta['item']
        item=SevendayItem()
        item['user']=item1['user']
        item['title'] = item1['title']
        item['read_qty'] = item1['read_qty']
        item['commend_qty'] = item1['commend_qty']
        item['admire_qty'] = item1['admire_qty']
        reward_detail = json.loads(response.text)
        reward_qty = reward_detail['rewards_count']
        print 'ssss',reward_qty
        item['reward']=reward_qty
        id=response.meta['id']
        html_collection_url = 'http://www.jianshu.com/notes/%s/included_collections.jason' % id
        yield Request(html_collection_url,meta={'item':item},callback=self.parse_collection)

    def parse_collection(self,response):
        item1=response.meta['item']
        item=SevendayItem()
        datas=[]
        collection_detail=json.loads(response.text)
        for one in collection_detail['collections']:
            datas.append(one['title'])
        data = ','.join(datas)
        item['topic']=data
        item['user'] = item1['user']
        item['title'] = item1['title']
        item['read_qty'] = item1['read_qty']
        item['commend_qty'] = item1['commend_qty']
        item['admire_qty'] = item1['admire_qty']
        item['reward']=item1['reward']
        yield item

重点分析sevenday.py部分知识点:

class sevenday(CrawlSpider):
    name='sevenday1'  #爬虫名字,
    start_urls=['http://www.jianshu.com/trending/weekly?utm_medium=index-banner-s&utm_source=desktop&page=1']
    def parse(self, response):
         urls = ['http://www.jianshu.com/trending/weekly?utm_medium=index-banner-s&utm_source=desktop&page={}'.format(i) for i in range(2, 9)]
         for newurl in urls:
            yield Request(newurl, callback=self.parse)

name='sevenday1'是爬虫名字,要和上边的类“sevenday"取不一样的名称,在main.py 会启动这个爬虫名称来运行爬虫
start_urls是启动爬虫最初进入的url
def parse(self, response):是一个用来解析这个start_urls的页面的函数。
其中response就是请求返回的响应的参数。
它的作用就像相当于单线程爬虫中的:

url='http://*****'
html=requests.get(url).content

可以用parse函数来解析start_urls的HTML源码来提取数据。例如:

 def parse(self, response):
    selector=Selector(response)
    datas=selector.xpath('//ul[@class="note-list"]/li')

类Selector是一个Scrapy的选择器。通过特定的XPath表达式来“选择” HTML文件中的某个部分。上边的例子通过xpath选取包含class="note-list"的标签ul下的li标签。通过网页分析,datas是一个列表。不确定的可以在这里打印datas看一下。
接上边,urls是一个新创建的url列表,通过for循环,游遍所有urls的地址.
yield Request(newurl, callback=self.parse) yield是提交的意思。callback是一个回调函数。本句的意思是将新的newurl重新回调给parse函数自身。然后parse函数收到新的newurl函数,解析newurl的网页代码。
另外,Request还可以在请求下一页解析的时候,将本页的数据通过meta传递给下一页。meta是一个字典。里边通过key对应value来传递给下一个回调对象。
方法如下:

yield Request(newurl, meta={'key1':'value1','key2':'value2'},callback=self.parse_info)
def parse_info(self,response)  #这里已经解析了newurl的网页代码,可以获取新的网页数据
      item1=SevendayItem()  #假定items.py的item名称是SevendayItem,将它实例化给item1,注意item1是一个字典。
      item1['key1']=response.meta['key1']  #response中meta中的key1的value赋予item['key1']
      item1['key2']=response.meta['key2']   #response中meta中的key2的value赋予item['key2']
      .....
      selector=Selector(response)  ##这里已经解析了newurl的网页代码
      value=selector.xpath('//../..').extract()[0]   #通过xpath获取newurl网页的相对应的数据,注意获取的数据需要在后边加上`.extract`,要不提取不出来  
      item1['key3']=value    #value赋予 item1['key3']
      yield item1   提交item1

yield item1提交最终的数据给items.py,如果还有数据在下一级网页,可以创建新的url,然后将item1的值赋予meta,继续请求新的url回调下一个parse_**

yield Request(新的url,meta={},callback=self.parse_**)
def parse_**(self,response)

“7日热点”遇到BUG的解决处理

由于打赏数据是异步加载,需要在界面中用正则表达式提取id,然后重新构造新的reward_rul,由于是json网页,所以需要用方法json.load解析网页,取出我们要rewards_count

Paste_Image.png

Paste_Image.png

以上2个图可以看到reward_url是在Request URL中,加载后的数据是在下图中的rewards_count:8
我刚开始做的时候和单线程爬虫一样,构造如下的reward_url:
rewards_url = ['http://www.jianshu.com/notes/{}/rewards.count=20'.format(str(id))][0]
然后将它提交,回调给下一个parse_info函数。
我在解析parse_info的时候,提取不出reward_count,生成的CSV文件是空的。于是打断点进行调试:运行debug时候,系统提示如下:

20170426_004111.jpg

中间有个DEBUG Forbidden by robots.txt ,然后去网上查找资料,有人说关闭scrapy自带的ROBOTSTXT_OBEY功能,在setting找到这个变量,设置为False即可解决。

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

然后再调试,还是有问题,如下:

11

于是 想起来可能是因为这个reward_url网页出错,但是里边的json数据还是有的,尝试改一下reward_url地址中?count=20改为.json如下:

 reward_url = ['http://www.jianshu.com/notes/{}/rewards.json'.format(str(id))]

运行成功!
专题也是异步加载,所以方法和打赏数据处理一样。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容