使用scrapy抓取人民网体育、社会模块

分析网站

刚开始看完网站的这两个模块,感觉很麻烦,需要写很多解析函数,写很多规则,对两个模块下的每个小模块逐个进行处理,然后就朝着这个方向开始写,写到一半发现,我不仅需要判断这个模块里有没有图片,还要判断这个模块属不属于图集,感觉应该是自己方向错了,于是就重新观察网站,结合之前写的解析,最后分析发现:
我所需的数据,无非就是文章标题,文章内容,文章里的图。只是页面结构不一样,并且2015年之前的页面,是属于老页面,现有的解析规则并不能够提取出数据,于是,先将所有解析规则合并到一起,然后去爬。将没有拿到title的页面的url存起来,分析为什么没有数据,最后得出:要么是这个网页本身不属于目标网页,要么是解析规则不够全面。对与不属于目标页面的网页,直接无视,然后对那些现有解析规则拿不到的页面,进行新的解析规则的定义,然后合并解析规则,反复多次,终于写出了算是完整规则。

开始写代码

最主要的是爬虫文件,像下载中间件,设置文件之类的,就不列出来了

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from ..items import RenminwangItem
# 在settings文件里定义好爬虫的名字,域,起始url,是因为社会模块和体育模块基本一样,解析规则可以直接拿来用
# 所以将这些东西放到设置里,方便切换
from ..settings import SPIDER_NAME, ALLOWED_DOMAINS, START_URLS


class TiyuSpider(CrawlSpider):
    name = SPIDER_NAME
    allowed_domains = ALLOWED_DOMAINS
    start_urls = START_URLS

    rules = (
        # 因为是要爬取模块下所有文章,所以就不用写链接提取规则了,只要是链接,就拿过来
        # 超出域的范围的,也就是不是体育模块的链接,是会被过滤掉的
        Rule(LinkExtractor(allow=()), follow=True, callback='parse_item'),
    )

    def parse_item(self, response):
        item = RenminwangItem()
        # 标题
        title = response.xpath("//h1/div/text() | //h1/text()").extract()
        self.check(item, title, 'title')
        # 正常文章的内容
        content_ls = response.xpath(
            "//p[@style='text-indent: 2em;']/text() | //p[@style='text-indent: 2em']/text() | //p[@style='text-indent: 2em']/text() | //div[@class='box_con']//p/text() | //div[@id='p_content']/p[not(@style)]/text() | //p[@style='text-indent: 2em;']/text() | //div[@id='p_content'][./text() and ./a//text()]").extract()
        content = ''.join(content_ls)
        # 文章里的插图链接
        inset_ls = response.xpath(
            "//div[@class='text w1000 clearfix']//div[@class='box_pic']//img/@src | //div[@class='box_pic']/following-sibling::p/img/@src | //*[@align='center']/img/@src").extract()
        inset = '+++'.join(inset_ls)

        # self.check(item,content_ls,'content')
        # self.check(item,inset_ls,'inset')

        item['content'] = content
        item['inset'] = inset
        item['url'] = str(response.url)

        return item
    # 这个函数是为了判断title是否为空,title为空的话,就拿出来看一下,看是什么原因导致的
    def check(self, item, type, name):
        if len(type) == 0:
            item[name] = 'kong_{}'.format(name)
        else:
            item[name] = ''.join(type)

因为设置了域,但是有些插图是不属于这个域的,所以要在管道文件,使用requests去下载图片
可以将下载其改成多线程或者异步,速度更快一点。

class DownLoadInsetPipeline(object):
    def process_item(self, item, spider):
        inset_list = item['inset'].split('+++')
        if inset_list[0] != '':
            for inset_url in inset_list:
                if inset_url.startswith('http://'):
                    # 图片的链接是完整的
                    dir_name = (item['url'].split('/')[-1]).replace('.html','')
                    #dir_path = 'E:\img\{}'.format(dir_name)
                    dir_path = BASE_DIR + dir_name
                    if not os.path.exists(dir_path):
                        os.makedirs(dir_path)
                    self.down_img(dir_path,inset_url)
                else:
                    img_url = BASE_URL + inset_url
                    html_name = (item['url'].split('/')[-1]).split('-')
                    if len(html_name) == 2:
                        dir_name = ''.join(html_name).replace('.html','')
                    else:
                        dir_name = ''.join(html_name[:-1])
                    #dir_path = 'E:\img\{}'.format(dir_name)
                    dir_path = BASE_DIR + dir_name
                    if not os.path.exists(dir_path):
                        os.makedirs(dir_path)
                    self.down_img(dir_path,img_url)
        return item
    def down_img(self,dir_path,img_url):
        file_name = dir_path + '\\' + img_url.split('/')[-1]
        resp = requests.get(img_url,timeout=30)
        resp.raise_for_status()
        resp.encoding = resp.apparent_encoding
        with io.open(file_name,'wb') as f:
            f.write(resp.content)

总结

遇到一个网站,开始爬取之前,一定要用结合需求,用心去分析网站,多思考,当整体逻辑出来了,程序自然而然就写出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值