Scrapy实现微信公众号文章爬取和分析
微信是近年来备受欢迎的社交媒体应用,在其中运营的公众号也扮演着非常重要的角色。众所周知,微信公众号是一个信息和知识的海洋,因为其中每个公众号都可以发布文章、图文消息等信息。这些信息可以被广泛地应用在很多领域中,比如媒体报道、学术研究等。
那么,本篇文章将介绍如何使用Scrapy框架来实现微信公众号文章的爬取和分析。Scrapy是一个Python的网络爬虫框架,其主要功能是进行数据挖掘和信息查找。因此,Scrapy具有很好的可定制性和高效性。
- 安装Scrapy并创建项目
要使用Scrapy框架进行爬虫,首先需要安装Scrapy和其他依赖项。可以使用pip命令进行安装,安装过程如下所示:
pip install scrapy
pip install pymongo
pip install mysql-connector-python
安装Scrapy之后,我们需要使用Scrapy命令行工具来创建项目。命令如下:
scrapy startproject wechat
执行该命令后,Scrapy将会创建一个名为“wechat”的项目,并在项目目录中创建许多文件和目录。
- 实现微信公众号文章的爬取
在我们开始爬虫之前,我们需要先搞懂微信公众号文章页面的URL格式。一个典型的微信公众号文章页面的URL长这样:
https://mp.weixin.qq.com/s?__biz=XXX&mid=XXX&idx=1&sn=XXX&chksm=XXX#wechat_redirect
其中,__biz 表示微信公众号的ID,mid 表示文章的ID,idx 表示文章的序号,sn 表示文章的签名,chksm 表示内容校验。因此,如果我们要爬取某个公众号的所有文章,就需要找到这个公众号的ID,并用它来构建URL。其中,biz_id 是该公众号的唯一标识。
首先,我们需要准备一个包含许多公众号ID的列表,因为我们要爬取这些公众号的文章。而ID的搜集可以通过各种手段来实现。在这里,我们使用一个包含几个测试ID的列表作为例子:
biz_ids = ['MzU5MjcwMzA4MA==', 'MzI4MzMwNDgwMQ==', 'MzAxMTcyMzg2MA==']
接着,我们需要编写一个Spider,来爬取某个公众号的所有文章。这里,我们将公众号的名字和ID传递到Spider,以方便我们可以处理不同的公众号ID。
import scrapy
import re
class WeChatSpider(scrapy.Spider):
name = "wechat"
allowed_domains = ["mp.weixin.qq.com"]
def __init__(self, name=None, biz_id=None):
super().__init__(name=name)
self.start_urls = ['https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz={}==#wechat_redirect'.format(biz_id)]
def parse(self, response):
article_urls = response.xpath('//h4[1]/a/@href')
for url in article_urls.extract():
yield scrapy.Request(url, callback=self.parse_article)
next_page = response.xpath('//a[@id="js_next"]/@href')
if next_page:
yield scrapy.Request(response.urljoin(next_page[0].extract()), callback=self.parse)
def parse_article(self, response):
url = response.url
title = response.xpath('//h2[@class="rich_media_title"]/text()')
yield {'url': url, 'title': title.extract_first().strip()}
Spider的主要功能是使用给定的公众号ID来访问公众号首页,然后递归地遍历每一页,提取所有文章的URL。此外,parse_article方法用于提取文章的URL和标题,以进行后续处理。总体而言,该Spider不是很复杂,但是提取速度较慢。
最后,我们需要在Terminal中输入下面的命令来启动Spider:
scrapy crawl wechat -a biz_id=XXXXXXXX
同样,我们也可以爬取多个公众号,只需要在命令中指定所有公众号的ID即可:
scrapy crawl wechat -a biz_id=ID1,ID2,ID3
- 存储文章数据
爬取文章之后,我们需要将文章的标题和URL保存到数据库(如MongoDB、MySQL等)。在这里,我们将使用pymongo库来保存爬取到的数据。
import pymongo
class MongoPipeline(object):
collection_name = 'wechat'
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
self.db[self.collection_name].insert_one(dict(item))
return item
在该Pipeline中,我们使用了MongoDB作为存储数据的后端。可以根据需要修改这个类来使用其他的数据库系统。
接下来,我们需要在settings.py文件中配置数据库相关的参数:
MONGO_URI = 'mongodb://localhost:27017/'
MONGO_DATABASE = 'wechat'
ITEM_PIPELINES = {'myproject.pipelines.MongoPipeline': 300}
最后,我们在Spider中调用Pipeline,以将数据存储到MongoDB中:
class WeChatSpider(scrapy.Spider):
name = "wechat"
allowed_domains = ["mp.weixin.qq.com"]
def __init__(self, name=None, biz_id=None):
super().__init__(name=name)
self.start_urls = ['https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz={}==#wechat_redirect'.format(biz_id)]
def parse(self, response):
article_urls = response.xpath('//h4[1]/a/@href')
for url in article_urls.extract():
yield scrapy.Request(url, callback=self.parse_article)
next_page = response.xpath('//a[@id="js_next"]/@href')
if next_page:
yield scrapy.Request(response.urljoin(next_page[0].extract()), callback=self.parse)
def parse_article(self, response):
url = response.url
title = response.xpath('//h2[@class="rich_media_title"]/text()')
yield {'url': url, 'title': title.extract_first().strip()}
pipeline = response.meta.get('pipeline')
if pipeline:
item = dict()
item['url'] = url
item['title'] = title.extract_first().strip()
yield item
在上面的代码中,response.meta.get('pipeline')是用来获取我们在Spider中设置的Pipeline的对象的。因此,只需在Spider代码中添加如下代码,就
.........................................................