微信文章关键词爬虫教程


前言

这是一个爬虫 Demo, 主要通过 Python 中的 urllib 库完成微信文章关键词爬虫,根据传入特定的关键词,爬取:微信|搜狗 的公众号文章,并且可以自定义爬取特定关键字的所在页面范围的文章。对链接的爬取主要通过 Regular Expression(RE) 完成,如果对正则表达式方面有疑问也没关系,我将最近写篇详细的正则的文章以供参考。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# -*- coding: utf-8 -*-
# 微信公众号文章爬虫
# Usage: 在get_all_article_url(keyword,start,end)提供需要查找的关键字、搜索的起始页和结束页,未使用proxy,如果爬取大量页面存在屏蔽风险
# 所有的/Users/rundouble/Desktop/为我自己的PC路径,运行需根据自己的路径进行修改
# TODO: proxy
import re
import urllib.request
import urllib.error
import time
headers = ('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36')
opener = urllib.request.build_opener()
opener.addheaders = [headers]
urllib.request.install_opener(opener)
# 用来存储所有的查找文章的链接
list_url = []
# k用来作为存储文章html文件的文件名
k = 'Default_Name'
# 根据url,返回源代码
def get_source(url):
try:
data = urllib.request.urlopen(url).read().decode('utf-8')
return data
except urllib.error.URLError as e:
if hasattr(e,'code'):
print(e.code)
if hasattr(e,'reason'):
print(e.reason)
time.sleep(3)
except Exception as e:
print('Exception:'+str(e))
time.sleep(1)
# 根据关键字、起始页和结束页,爬取所有该关键字的公众号文章的链接
def get_all_article_url(key, start, end):
try:
global k
k = key
keycode = urllib.request.quote(key)
pagecode = urllib.request.quote('&page')
# 构建文章目录网址
for page in range(start, end+1):
# 记得type参数,type=2表示文章,不写type为公众号
url = 'http://weixin.sogou.com/weixin?query='+keycode+'&type=2'+'&page='+str(page)
data1 = get_source(url)
# .*?是懒惰模式,并且该pattern最后的字符是一个双引号,只是获得()url内容
listurl_pat = '<div class="txt-box">.*?(http://.*?)"'
# 使用预编译可以将整个文本中所有满足模式的链接提取出来,以列表形式存储
list_url.append(re.compile(listurl_pat, re.S).findall(data1))
print('Total articles\' url size:'+str(len(list_url))+'个')
for url in list_url:
print(url)
return list_url
except urllib.error.URLError as e:
if hasattr(e,'code'):
print(e.code)
if hasattr(e, 'reason'):
print(e.reason)
time.sleep(3)
except Exception as e:
print("Exception:"+str(e))
time.sleep(1)
# 根据需要查找的公众号文章的url,爬取文章内容
def get_content(list_url):
head_html = '''
<html>
<head>
<meta charset="utf-8"/>
<title>爬取的微信文章简易展示</title>
</head>
<body>
'''
fhandle = open('/Users/rundouble/Desktop/'+k+'.html', 'wb')
fhandle.write(head_html.encode('utf-8'))
fhandle.close()
# 遍历list_url(二维表)
for i in range(0, len(list_url)):
for j in range(0, len(list_url[i])):
try:
# trim article url
url = list_url[i][j]
print(url)
url = url.replace('amp;', '')
data = get_source(url)
title_pat = '<title>(.*?)</title>'
content_pat = 'id="js_content">(.*?)id="js_sg_bar">'
title = re.compile(title_pat).findall(data)
content = re.compile(content_pat,re.S).findall(data)
this_title = 'No title'
this_content = 'No content'
if title:
this_title = title[0]
if content:
this_content = content[0]
article_data = '<p>'+this_title+'</p><br>'+'<p>'+this_content+'</p><br>'
fhandle = open('/Users/rundouble/Desktop/'+k+'.html', 'ab')
fhandle.write(article_data.encode('utf-8'))
fhandle.close()
print('第'+str(i)+'个页面,第'+str(j)+'个文章正在写入。')
except urllib.error.URLError as e:
if hasattr(e, 'code'):
print(e.code)
if hasattr(e, 'reason'):
print(e.reason)
time.sleep(3)
except Exception as e:
print('Exception:'+str(e))
time.sleep(1)
fhandle.close()
foot_html = '</body></html>'
fhandle = open('/Users/rundouble/Desktop/'+k+'.html','ab')
fhandle.write(foot_html.encode('utf-8'))
fhandle.close()
list_url = get_all_article_url('知乎›', 1, 2)
get_content(list_url)

结果

将所有爬取的文章存储在以搜索关键字为名字的html文件中,比如,我以“知乎”为关键字,运行后,会有一个“知乎.html”的文件,打开:

思路

微信|搜狗 可以搜索微信公众号和微信公众号文章,本教程只做文章的爬虫。当我们输入关键字“知乎”的时候,根据对比搜索时的网址URL发现

type=2 表示搜索文章,不写 type默认查找的是公众号
query的值是要搜索的关键字,但由于是经过编码处理,所以在程序中要使用quote()方法对关键字进行utf-8的处理

这样就构建好搜索时的URL模板,不同的关键字搜索只需要更改query的值就可以。
当我们跳转搜索结果的第二页再次观察URL

这时增加了两个字段,一个是ie,代表编码格式,可以不管它。另一个是page=2,不难发现是控制搜索页的页数。
当我们搜索关键字时,进入预览页

这时需要获得当前页的所有的文章的链接,观察源代码

发现每篇文章的链接都是以

开头,在这个div中的第一个URL就是我们想要的文章链接,所以使用正则表达式的非贪婪模式,并且URL是以 http 开头,并以一个双引号结束, 正则表达式为:
.?(http://.?)” 这样就可以找出所有的当前页面的所有文章的链接。根据用户传进的需要爬取的文章页面数,把范围内所有的文章URL使用List存储。

在进入每篇具体的文章页面时,再次观察源码

找到文章标题所在的 标签,使用正则表达式:<title>(.*?) 提取标题。
最后提取文章正文,这个正文是包含一些样式的,把整个文章的爬取出来

以id=”js_content”开头,以 id=”js_sg_bar” 结尾的之间的内容为文章的全文信息,使用正则表达式:id=”js_content”>(.*?)id=”js_sg_bar”> 。最后通过构建一个简易的h5的文件,将文章的标题和文章内容填入进去,done.

主要通过三个方法实现:

  • 第一个是get_resource(url),传入URL,返回网页的源码

  • 第二个是get_all_article_url(key, start, end) 传入关键字、起始页、结束页,返回范围内的文章的URL

  • 第三个是get_content(list_url) 传入文章的URL列表,这个列表是二维的,因为每行代表每个搜索页的文章的URL列表,因为有多个搜索页面,所以实质上是二维表,该方法返回完成文章内容的爬取

改进

  • 如果大批量爬取微信公众号文章会造成IP被封的可能,所以可以使用proxy,为程序使用代理,避免屏蔽
  • 另一方面,在爬取文章的内容存储时候,可以把h5的样式调整,以更加优雅的方式呈现
  • 采用多线程方式爬取
Demo以“知乎”为关键字爬虫结果:知乎.html
-------------本文结束感谢您的阅读-------------