博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
scrapy抓取中国新闻网新闻
阅读量:4580 次
发布时间:2019-06-09

本文共 7502 字,大约阅读时间需要 25 分钟。

目标说明

利用scrapy抓取中新网新闻,关于自然灾害滑坡的全部国内新闻;要求主题为滑坡类新闻,包含灾害造成的经济损失等相关内容,并结合textrank算法,得到每篇新闻的关键词,便于后续文本挖掘分析。

网站分析

目标网站:

结合中新搜索平台的高级搜索的特点,搜索关键词设置为:滑坡 经济损失(以空格隔开),设置分类频道为国内,排序方式按照相关度。得到所有检索到的新闻如下:

共1000多条数据。

分析网站特点发现,给请求为异步加载,通过抓包工具Fiddler得到:

分析:

  POST提交,每次提交目标的url为:http://sou.chinanews.com/search.do

  提交参数如上所示,其中q表示关键词(抓包测试时只输入了一个关键词);

  ps表示每次显示的调试,adv=1表示高级搜索;day1,day2表示搜索时间,默认不写表示全部时间,channel=gn表示国内;

  继续点击下一页,通过对照得到一个新的参数:start,其中当start=0时,默认省略,表示第一页,每次下一页都增加10(设置的页面显示10)

   分析得到,每次点击下一页都是一个POST提交,参数相同,不同的是start

代码逻辑

使用命令:scrapy start project NewsChina创建项目,编写items.py文件,明确抓取字段(常用套路,第一步都是明确抓取字段)。这里只抓取标题和正文。常规操作:添加数据来源和抓取时间信息。

# -*- coding: utf-8 -*-# Define here the models for your scraped items## See documentation in:# https://doc.scrapy.org/en/latest/topics/items.htmlimport scrapyclass NewschinaItem(scrapy.Item):    # define the fields for your item here like:    # name = scrapy.Field()    # 数据来源    source = scrapy.Field()    # 抓取时间    utc_time = scrapy.Field()    # 新闻标题    title = scrapy.Field()    # 新闻内容    content = scrapy.Field()    # 关键词    keywords = scrapy.Field()

 

明确抓取字段后,使用命令:scrapy genspider newsChina 生成爬虫,开始编写爬虫逻辑,结合抓取网站的特点,做以下操作:

针对该网站的反爬措施,添加请求延迟、重试次数等待配置;

通过修改POST请求的time_scope字段,得到每一页数据,并解析数据中详情页的链接,然后对详情页链接请求,解析待抓取数据;

至于循环抓取和终止循环条件,结合实际网站各有不同,在代码中已有说明。

# -*- coding: utf-8 -*-import reimport scrapyfrom NewsChina.items import NewschinaItemclass NewschinaSpider(scrapy.Spider):    name = 'newsChina'    # allowed_domains = ['sou.chinanews.com']    # start_urls = ['http://http://sou.chinanews.com/']    #爬虫设置    # handle_httpstatus_list = [403]  # 403错误时抛出异常    custom_settings = {        "DOWNLOAD_DELAY": 2,        "RETRY_ENABLED": True,    }    page = 0    # 提交参数    formdata = {        'field': 'content',        'q': '滑坡 经济损失',        'ps': '10',        'start': '{}'.format(page * 10),        'adv': '1',        'time_scope': '0',        'day1': '',        'day2': '',        'channel': 'gn',        'creator': '',        'sort': '_score'    }    # 提交url    url = 'http://sou.chinanews.com/search.do'    def start_requests(self):        yield scrapy.FormRequest(            url=self.url,            formdata=self.formdata,            callback=self.parse        )    def parse(self, response):        try:            last_page = response.xpath('//div[@id="pagediv"]/span/text()').extract()[-1]            # 匹配到尾页退出迭代            if last_page is '尾页':                return        except:            # 当匹配不到last_page时,说明已经爬取所有页面,xpath匹配失败            # 抛出异常,这就是我们的循环终止条件            # print("last_page:", response.url)            return        link_list = response.xpath('//div[@id="news_list"]/table//tr/td/ul/li/a/@href').extract()        for link in link_list:            if link:                item = NewschinaItem()                # 访问详情页                yield scrapy.Request(link, callback=self.parse_detail, meta={
'item': item}) # 循环调用,访问下一页 self.page += 1 # 下一页的开始,修改该参数得到新数据 self.formdata['start'] = '{}'.format(self.page * 10) yield scrapy.FormRequest( url=self.url, formdata=self.formdata, callback=self.parse ) # 从详情页中解析数据 def parse_detail(self, response): """ 分析发现,中新网年份不同,所以网页的表现形式不同, 由于抓取的是所有的数据,因此同一个xpath可能只能匹配到部分的内容; 经过反复测试发现提取规则只有如下几条。提取标题有两套规则 提取正文有6套规则。 :param response: :return: """ item = response.meta['item'] # 提取标题信息 if response.xpath('//h1/text()'): item['title'] = response.xpath('//h1/text()').extract_first().strip() elif response.xpath('//title/text()'): item['title'] = response.xpath('//title/text()').extract_first().strip() else: print('title:', response.url) # 提取正文信息 try: if response.xpath('//div[@id="ad0"]'): item['content'] = response.xpath('//div[@id="ad0"]').xpath('string(.)').extract_first().strip() elif response.xpath('//div[@class="left_zw"]'): item['content'] = response.xpath('//div[@class="left_zw"]').xpath('string(.)').extract_first().strip() elif response.xpath('//font[@id="Zoom"]'): item['content'] = response.xpath('//font[@id="Zoom"]').xpath('string(.)').extract_first().strip() elif response.xpath('//div[@id="qb"]'): item['content'] = response.xpath('//div[@id="qb"]').xpath('string(.)').extract_first().strip() elif response.xpath('//div[@class="video_con1_text_top"]/p'): item['content'] = response.xpath('//div[@class="video_con1_text_top"]/p').xpath('string(.)').extract_first().strip() else: print('content:', response.url) except: # 测试发现中新网有一个网页的链接是空的,因此提前不到正文,做异常处理 print(response.url) item['content'] = '' yield item

 

编写中间件,添加随机头信息:

# -*- coding: utf-8 -*-# Define here the models for your spider middleware## See documentation in:# https://doc.scrapy.org/en/latest/topics/spider-middleware.htmlimport randomfrom NewsChina.settings import USER_AGENTS as uaclass NewsChinaSpiderMiddleware(object):    def process_request(self, request, spider):        """        给每一个请求随机分配一个代理        :param request:        :param spider:        :return:        """        user_agent = random.choice(ua)        request.headers['User-Agent'] = user_agent

 

编写数据保存逻辑:

结合python的jieba模块的textrank算法,实现新闻的关键词抽取,并保存到excel或数据库中

# -*- coding: utf-8 -*-# Define your item pipelines here## Don't forget to add your pipeline to the ITEM_PIPELINES setting# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.htmlfrom datetime import datetimefrom jieba import analysefrom openpyxl import Workbookimport pymysqlclass KeyswordPipeline(object):    """    添加数据来源及抓取时间;    结合textrank算法,抽取新闻中最重要的5个词,作为关键词    """    def process_item(self, item, spider):        # 数据来源        item['source'] = spider.name        # 抓取时间        item['utc_time'] = str(datetime.utcnow())        content = item['content']        keywords = ' '.join(analyse.textrank(content, topK=5))        # 关键词        item['keywords'] = keywords        return itemclass NewsChinaExcelPipeline(object):    """    数据保存    """    def __init__(self):        self.wb = Workbook()        self.ws = self.wb.active        self.ws.append(['标题', '关键词', '正文', '数据来源', '抓取时间'])    def process_item(self, item, spider):        data = [item['title'], item['keywords'], item['content'], item['source'], item['utc_time']]        self.ws.append(data)        self.wb.save('./news.xls')        return item# class NewschinaPipeline(object):#     def __init__(self):#         self.conn = pymysql.connect(#             host='.......',#             port=3306,#             database='news_China',#             user='z',#             password='136833',#             charset='utf8'#         )#         # 实例一个游标#         self.cursor = self.conn.cursor()##     def process_item(self, item, spider):#         sql = """#               insert into ChinaNews(ID, 标题, 关键词, 正文, 数据来源, 抓取时间)#                values (%s, %s, %s, %s, %s, %s);"""##         values = [#             item['title'],#             item['keywords'],#             item['content'],##             item['source'],#             item['utc_time']#         ]##         self.cursor.execute(sql, values)#         self.conn.commit()##         return item##     def close_spider(self, spider):#         self.cursor.close()#         self.conn.close()

运行结果

完成代码

 参见:

 

转载于:https://www.cnblogs.com/pythoner6833/p/9234983.html

你可能感兴趣的文章