python爬虫如何爬取微信公众号文章
在爬虫如何爬取微信公众号文章这篇文章中介绍了如何获取公众号的所有历史文章的链接,并保存在了csv文件中,接下来介绍如何通过这些url地址爬取每篇文章,并通过xpath和正则表达式提取出一些重要的数据,把数据保存到数据库并把整个页面保存起来。
1.首先定义一个类,并定义一些超参数,这里只用到了User_Agent:
class WeixinSpider_1:
def __init__(self):
self.headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36"}
2.读取文件,把每篇文章的url地址和发布时间传入到两个列表中:
def get_url_list(self):
file_path = "url/beijing.csv"
df = pd.read_csv(file_path)
url_list = df["link"].tolist()
time_list = df["create_time"].tolist()
return url_list, time_list
tolist()方法是将pandas中的Series类型的数据转换成list类型。返回两个列表,url列表和发布时间列表。
3.解析url地址,发送请求获得响应,返回页面源码
def parse_url(self, url):
response = requests.get(url, headers=self.headers)
return response.content.decode()
这里要介绍一下str和bytes两种数据类型,bytes是二进制类型,互联网上的数据都是以二进制的方式传输的。
str是unicode的呈现形式,unicode是字符集。
字符集包括:ASCII字符集、GB2312字符集、GB18030字符集、Unicode字符集等
UTF-8是Unicode的实现方式之一,UTF-8是一种变长的编码方式,可以是1,2,3个字节。
网页上的是bytes类型数据,所以需要转换成str类型。
str 使用encode方法转化为 bytes
bytes通过decode转化为str。
为什么要用request而不是urllib呢?
- requests的底层实现就是urllib
- requests在python2 和python3中通用,方法完全一样
- requests简单易用
- Requests能够自动帮助我们解压(gzip压缩的等)网页内容
response的常用方法:
- response.text
- respones.content
- response.status_code
- response.request.headers
- response.headers
response.text 和response.content比较
类型 | 解码类型 | 修改编码方式 | |
---|---|---|---|
response.text | str | 根据HTTP 头部对响应的编码作出有根据的推测,推测的文本编码 | response.encoding=”gbk” |
response.content | bytes | 没有指定 | response.content.deocde(“utf8”) |
4.分析页面,提取数据
使用xpath取出文章的标题,公众号的名称和文章文本内容,然后返回一个字典列表。
def get_content_list(self, html_str): # 提取数据
html = etree.HTML(html_str)
content_list = []
item = {}
item["title"] = html.xpath("//*[@id=\"activity-name\"]/text()")
item["title"] = [i.replace("\n", "").replace(" ", "") for i in item["title"]]
item["laiyuan"] = html.xpath("//*[@id=\"js_name\"]/text()")
item["laiyuan"] = [i.replace("\n", "").replace(" ", "") for i in item["laiyuan"]]
item["other"] = html.xpath("//*[@id=\"js_content\"]//text()")
content_list.append(item)
return content_list
5.保存html的函数:
def save_html(self, html_str, page_name):
file_path = "html/lufa/{}.html".format(page_name)
with open(file_path, "w", encoding="utf-8") as f:
f.write(html_str)
6.实现主要逻辑:
def run(self):
# 获取url列表和时间列表
url_list, time_list = self.get_url_list()
# 打开数据库连接(ip/数据库用户名/登录密码/数据库名)
db = pymysql.connect("localhost", "root", "root", "weixin_database")
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
# 遍历url列表,发送请求,获取响应
for url in url_list:
num = url_list.index(url)
print(num)
# 解析url,获得html
html_str = self.parse_url(url)
# 获取内容
content_list = self.get_content_list(html_str)
# list转字符串
title = ''.join(content_list[0]["title"])
other = '\n'.join(content_list[0]["other"])
# 根据下标取发布时间
create_time = time_list[num]
需要匹配出案件号,一般是(2018)最高法行申11236号
这种格式的,有的还是(2018)最高88法行申11236号
这样的,匹配规则是这样\s*[(|(]20\d+[)|)]\s*[\u4e00-\u9fa5]*[\d]*[\u4e00-\u9fa5]+[\d]+号
p1 = re.compile(r'\s*[(|(]20\d+[)|)]\s*[\u4e00-\u9fa5]*[\d]*[\u4e00-\u9fa5]+[\d]+号', re.S)
anhao = re.search(p1, other)
if (anhao):
anhao = anhao.group().replace("\n", "")
else:
anhao = ""
对于公众号文章,每一篇的内容都在同一个div中,而且全是<p>
标签,并且没有选择器id
和class
,所以想要单独取出某部分内容比较麻烦。
所以使用正则表达式取出文章的一些重要的文字,如图想要匹配出裁判要点中的所有文字
p2 = re.compile(r'\s[【]*裁判要点\s*.*?(?=[【]|裁判文)', re.S)
zhaiyao = ''.join(re.findall(p2, other)).replace("\n", "")
还想取出所有文本的那个div,然后可以按照它的格式在自己的网页中显示
p3 = re.compile('<div class="rich_media_content " id="js_content">.*?</div>', re.S)
html = re.search(p3, html_str)
if (html):
html = re.search(p3, html_str).group().replace("\n", "")
else:
html = html_str.replace("\n", "")
page_name = title
self.save_html(html, page_name)
把取出的数据保存到数据库中
sql = """INSERT INTO weixin_table(title,url,anhao,yaozhi,other,html,create_time,type_id)
VALUES ({},{},{},{},{},{},{},{})""".format('"' + title + '"', '"' + url + '"', '"' + anhao + '"',
'"' + zhaiyao + '"', '"' + other + '"', "'" + html + "'",
create_time, 4)
# print(sql)
try:
# 执行sql语句
cursor.execute(sql)
# 提交到数据库执行
db.commit()
except:
print("数据插入失败:")
info = sys.exc_info()
print(info[0], ":", info[1])
# 如果发生错误则回滚
db.rollback()
# 关闭数据库连接
db.close()
7.运行程序:
if __name__ == '__main__':
weixin_spider = WeixinSpider_1()
weixin_spider.run()
8.数据库中保存的数据:
9.有了数据之后就可以在自己的网页里显示了。