摘要:此案例是爬取目标网站(https://tipdm.com/)的新闻中心板块的公司新闻中所有新闻的标题、发布时间、访问量和新闻的文本内容。

1. 创建scrapy项目

我使用的是 Anaconda prompt 我们使用如下命令创建scrapy项目:scrapy startproject spider_name 爬虫路径

spider_name是项目的名字 爬虫路径就是项目所在位置

本案例内命令是:scrapy startproject mySpider 路径

2. 生成爬虫器

我们先生成 spider(爬虫器) 文件:scrapy genspider spider_name domain

spider_name:是生成的 爬虫器的名字,在目录spiders 下面domain:是要爬取的网站的域名(一般是不加http,只写www.xxx.com就行)

本案例内,命令是scrapy genspider msd www.tipdm.com

3. 指定爬取字段(items.py)

指定要爬取的内容都有什么,我们在摘要中已经说明,要爬取的是 所有新闻的标题、发布时间、访问量和新闻的文本内容。 所以有四个字段,代码如下:

import scrapy

class MyspiderItem(scrapy.Item):

title = scrapy.Field()

time = scrapy.Field()

view = scrapy.Field()

text = scrapy.Field()

4. 编写爬虫文件(msd.py)

我们要爬取的是:所有页面的、所有新闻的内容。 所以我们写三个parse函数。

parse:得到页数,并得到每页的网址,传给下个函数parse_url:得到每个页面的所有新闻的链接parse_text:分析得到的新闻界面的内容,并存入 item 中,返回回去

注意:将 start_url 修改成第一个要爬取的页面,即公司新闻的页面

(代码中注释掉的内容都是调试用的)

parse函数

先得到总页数,因为取出来的是 str,将其转成int类型。 通过取出各个页面可知,每个页面的网址类似,只有数字不同,我们就可以生成网址了。 然后使用 yield Request() 回调下一个函数。 现在还不太懂原理。yield ,并不会直接返回,而是会返回一个生成器,可以遍历完所有的网页再统一返回

def parse(self, response):

number = int(response.xpath('//*[@id="t251"]/div[6]/div/a[6]/text()').extract()[0]) # 总页数

url_all = ['http://www.tipdm.com/gsxw/index_{}.jhtml'.format(i) for i in range(1, number + 1)]

for i in url_all:

yield Request(url=i, callback=self.parse_url, dont_filter=True)

parse_url

得到单个页面中的所有新闻的网址,放在一个列表中 注意:这里被卡了好久,就是因为得到的网址是不完整的,没有前缀(http之类的)一直进不到下一个函数(可以在每个函数写一个输出语句,以便检查是否进入了函数) 所以我们将url补充完毕,进行回调 爬取不出来的时候,一定要输出一下网址看看

def parse_url(self, response):

urls = response.xpath('//*[@id="t251"]/div/div[3]/h1/a/@href').extract()

for i in urls:

yield Request(url=('http://www.tipdm.com' + i), callback=self.parse_text, dont_filter=True)

parse_text

本函数是分析新闻的内容的函数,并存储在item中返回 有个很尴尬的点是这个网站的前端有点乱,有几条新闻的文本内容的xpath路径和其他的都不一样,好麻烦的,现在还不知道怎么解决

def parse_text(self, response):

item = MyspiderItem()

item['title'] = response.xpath('/html/body/div[2]/div/div[1]/div[2]/h1/text()').extract() # title

item['time'] = response.xpath('/html/body/div[2]/div/div[1]/div[2]/div/div[1]/span[1]/text()').extract() # time

item['view'] = response.xpath('/html/body/div[2]/div/div[1]/div[2]/div/div[1]/span[3]/text()').extract() # view

item['text'] = '\n'.join(response.xpath('/html/body/div[2]/div/div[2]/p/text()').extract())

if item['text'] == '':

item['text'] = '\n'.join(response.xpath('/html/body/div[2]/div/div[2]/p/span/text()').extract())

if item['text'] == '':

item['text'] = '\n'.join(response.xpath('/html/body/div[2]/div/div[2]/section[2]/section/section[2]/section[2]/p/span/text()').extract())

return item

完整代码

import scrapy

from scrapy.http import Request

from mySpider.items import MyspiderItem

class MsdSpider(scrapy.Spider):

name = 'msd'

allowed_domains = ['www.tipdm.com']

start_urls = ['http://www.tipdm.com/gsxw/index.jhtml']

def parse(self, response):

number = int(response.xpath('//*[@id="t251"]/div[6]/div/a[6]/text()').extract()[0]) # 总页数

url_all = ['http://www.tipdm.com/gsxw/index_{}.jhtml'.format(i) for i in range(1, number + 1)]

for i in url_all:

# print('1111111111111111')

yield Request(url=i, callback=self.parse_url, dont_filter=True)

# print(i)

def parse_url(self, response):

urls = response.xpath('//*[@id="t251"]/div/div[3]/h1/a/@href').extract()

# print('22222222222222222222')

for i in urls:

yield Request(url=('http://www.tipdm.com' + i), callback=self.parse_text, dont_filter=True)

def parse_text(self, response):

# print('77')

item = MyspiderItem()

# print('78')

item['title'] = response.xpath('/html/body/div[2]/div/div[1]/div[2]/h1/text()').extract() # title

# print('7999')

item['time'] = response.xpath('/html/body/div[2]/div/div[1]/div[2]/div/div[1]/span[1]/text()').extract() # time

item['view'] = response.xpath('/html/body/div[2]/div/div[1]/div[2]/div/div[1]/span[3]/text()').extract() # view

item['text'] = '\n'.join(response.xpath('/html/body/div[2]/div/div[2]/p/text()').extract())

if item['text'] == '':

item['text'] = '\n'.join(response.xpath('/html/body/div[2]/div/div[2]/p/span/text()').extract())

if item['text'] == '':

item['text'] = '\n'.join(response.xpath('/html/body/div[2]/div/div[2]/section[2]/section/section[2]/section[2]/p/span/text()').extract())

# print('79')

return item

5. 存储数据(pipelines.py、settings.py)

我们选择使用pipelines存储,需要在settings文件中取消相应代码注释

settings.py

ITEM_PIPELINES = {

'mySpider.pipelines.MyspiderPipeline': 300,

}

pipelines.py

因为我选择存储为.csv文件,所以需要导入pandas 注意:to_csv中,参数顺序不能乱

其中,参数的顺序如下:

filename: 文件名,必需。index: 是否写入行索引,可选。默认为False。encoding: 字符编码,可选。默认为utf-8-sig。compression: 压缩模式,可选。默认为gzip。header: 表头是否写入,可选。默认为None。footer: 表尾是否写入,可选。默认为None。newline: 换行符,可选。默认为None。dtype: 数据类型,可选。默认为None。optimizer: 优化器,可选。默认为None。写入文件的写入器对象: 写入文件的写入器对象,可选。默认为None。写入文件的参数: 写入文件的参数,可选。默认为None。 需要注意的是,header和footer参数默认为None,表示不写入表头和表尾。如果希望写入表头或表尾,可以设置该参数为True。

import pandas as pd

from itemadapter import ItemAdapter

class MyspiderPipeline:

def process_item(self, item, spider):

data = pd.DataFrame(dict(item))

data.to_csv('data2.csv', mode='a+', index=None, encoding='utf-8-sig', header=None)

return item

好文阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: