声明本文仅供学习交流请勿用于非法用途一、前言这个项目其实挺实用的比如你想收集某个领域的文章做分析或者单纯想批量保存一些干货都能用得上。核心思路就是通过搜狗微信搜索按关键词抓文章链接再逐个下载保存成HTML。二、需求分析2.1 爬取目标入口网站搜狗微信搜索 (http://weixin.sogou.com)目标数据指定关键词下的微信公众号文章标题正文输出格式单个HTML文件包含所有抓取到的文章主要难点搜狗的反爬、微信文章链接的amp;编码问题、正则提取的容错处理2.2 技术选型技术/库用途urllib.request发送HTTP请求本文用标准库不依赖第三方re正则提取文章链接和内容time请求间隔防止被封三、数据来源分析3.1 搜狗微信搜索的URL规律打开搜狗微信搜索随便搜个词比如小米看地址栏http://weixin.sogou.com/weixin?type2query%E5%B0%8F%E7%B1%B3ieutf8s_frominput_sug_n_sug_type_1参数拆解type2搜索文章type1是搜公众号queryxxx搜索关键词URL编码后的其他参数基本都是固定的可以忽略点下一页地址变成http://weixin.sogou.com/weixin?query%E5%B0%8F%E7%B1%B3page2type2多了个page2这就是翻页参数每页10条结果。3.2 文章链接的定位F12打开开发者工具看Elements面板文章链接都在classtxt-box的div下面divclasstxt-boxh3ahrefhttp://mp.weixin.qq.com/...target_blank文章标题/a/h3/div用正则匹配这个结构提取href就行。3.3 微信文章页面的结构打开一篇微信文章看源码标题在title标签里正文在idjs_content的div里这两个地方就是我们最终要抓的内容。四、代码实现4.1 下载模块先封装一个通用的下载函数后面复用importurllib.requestimporttimeimporturllib.errordefdownloader(url):headers(User-Agent,Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.4793.400 QQBrowser/10.0.702.400)openerurllib.request.build_opener()opener.addheaders[headers]urllib.request.install_opener(opener)try:dataurllib.request.urlopen(url).read()datadata.decode(utf-8)returndataexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)这里用了urllib.request而不是requests主要是想展示一下标准库的用法实际项目中两个都可以。4.2 获取文章链接列表defgetlisturl(key,pagestart,pageend):try:pagepagestart keycodeurllib.request.quote(key)pagecodeurllib.request.quote(page)forpageinrange(pagestart,pageend1):urlhttp://weixin.sogou.com/weixin?type2querykeycodepagecodestr(page)data1downloader(url)listurlpatdiv classtxt-box.*?(http://.*?)data2re.compile(listurlpat,re.S)resultdata2.findall(data1)listurl.append(result)print(共获取到str(len(listurl))页)returnlisturlexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)关键点urllib.request.quote(key)把中文关键词转成URL编码正则里的re.S让.能匹配换行符因为HTML里标签可能换行返回的是二维列表外层是页内层是每页的文章链接4.3 下载并保存文章defgetcontent(listurl):i0# HTML文件头部html1!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd html xmlnshttp://www.w3.org/1999/xhtml head meta http-equivContent-Type contenttext/html; charsetutf-8 / title微信文章页面/title /head bodyfhopen(1.html,wb)fh.write(html1.encode(utf-8))fh.close()fhopen(1.html,ab)foriinrange(0,len(listurl)):forjinrange(0,len(listurl[i])):try:urllisturl[i][j]# 搜狗给的链接里带了amp;得去掉才能正常访问urlurl.replace(amp;,)datadownloader(url)# 提取标题titlepattitle(.*?)/title# 提取正文contentpatidjs_content(.*?)idjs_sg_bartitlere.compile(titlepat).findall(data)contentre.compile(contentpat,re.S).findall(data)if(title![]):thistitletitle[0]if(content![]):thiscontentcontent[0]# 组装成HTML段落写入文件dataallp标题为:thistitle/pp内容为:thiscontent/pbrfh.write(dataall.encode(utf-8))print(第str(i1)个网页第str(j1)条内容保存)excepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)fh.close()# HTML文件尾部html2/body /html fhopen(1.html,ab)fh.write(html2.encode(utf-8))fh.close()这里有几个要注意的地方amp;问题搜狗返回的链接里带了amp;这是HTML实体编码直接访问会404必须replace(amp;, )去掉。正则容错title和content可能匹配不到页面结构变了或者文章被删了所以加了! []的判断。文件模式先用wb写头部再用ab追加内容最后追加尾部。4.4 完整代码importreimporturllib.requestimporttimeimporturllib.errordefdownloader(url):headers(User-Agent,Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.4793.400 QQBrowser/10.0.702.400)openerurllib.request.build_opener()opener.addheaders[headers]urllib.request.install_opener(opener)try:dataurllib.request.urlopen(url).read()datadata.decode(utf-8)returndataexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)defgetlisturl(key,pagestart,pageend):try:pagepagestart keycodeurllib.request.quote(key)pagecodeurllib.request.quote(page)forpageinrange(pagestart,pageend1):urlhttp://weixin.sogou.com/weixin?type2querykeycodepagecodestr(page)data1downloader(url)listurlpatdiv classtxt-box.*?(http://.*?)data2re.compile(listurlpat,re.S)resultdata2.findall(data1)listurl.append(result)print(共获取到str(len(listurl))页)returnlisturlexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)defgetcontent(listurl):i0html1!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd html xmlnshttp://www.w3.org/1999/xhtml head meta http-equivContent-Type contenttext/html; charsetutf-8 / title微信文章页面/title /head bodyfhopen(1.html,wb)fh.write(html1.encode(utf-8))fh.close()fhopen(1.html,ab)foriinrange(0,len(listurl)):forjinrange(0,len(listurl[i])):try:urllisturl[i][j]urlurl.replace(amp;,)datadownloader(url)titlepattitle(.*?)/titlecontentpatidjs_content(.*?)idjs_sg_bartitlere.compile(titlepat).findall(data)contentre.compile(contentpat,re.S).findall(data)if(title![]):thistitletitle[0]if(content![]):thiscontentcontent[0]dataallp标题为:thistitle/pp内容为:thiscontent/pbrfh.write(dataall.encode(utf-8))print(第str(i1)个网页第str(j1)条内容保存)excepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)fh.close()html2/body /html fhopen(1.html,ab)fh.write(html2.encode(utf-8))fh.close()if__name____main__:listurllist()keystr(input(请输入要查询的关键词))pagestart1pageendint(input(请输入结束页码(每页保存10条内容)))listurlgetlisturl(key,pagestart,pageend)getcontent(listurl)五、几个容易踩的坑5.1 搜狗反爬搜狗的反爬不算特别严但爬多了也会弹验证码。建议每页之间加time.sleep(1)或更久如果需要大规模采集考虑上代理IP代码里留了代理模块的注释需要的可以放开5.2 微信文章链接失效有些文章可能被删了或者公众号设置了权限打开会提示该内容已被发布者删除。这种情况正则匹配到的内容为空代码里加了! []的判断不会崩但会跳过这篇文章。5.3 正文提取不完整微信文章的正文有时候结构不太统一比如有的带js_sg_bar有的不带。如果抓到的内容少了可以调一下正则表达式或者改用BeautifulSoup解析容错性更好。六、运行效果运行程序后输入关键词和页码请输入要查询的关键词Python 请输入结束页码(每页保存10条内容)3 共获取到3页 第1个网页第1条内容保存 第1个网页第2条内容保存 ... 第3个网页第10条内容保存同级目录下会生成一个1.html用浏览器打开就能看到所有抓取到的文章标题和正文都在里面。
Python爬虫实战(十六):搜狗微信文章采集与HTML导出
声明本文仅供学习交流请勿用于非法用途一、前言这个项目其实挺实用的比如你想收集某个领域的文章做分析或者单纯想批量保存一些干货都能用得上。核心思路就是通过搜狗微信搜索按关键词抓文章链接再逐个下载保存成HTML。二、需求分析2.1 爬取目标入口网站搜狗微信搜索 (http://weixin.sogou.com)目标数据指定关键词下的微信公众号文章标题正文输出格式单个HTML文件包含所有抓取到的文章主要难点搜狗的反爬、微信文章链接的amp;编码问题、正则提取的容错处理2.2 技术选型技术/库用途urllib.request发送HTTP请求本文用标准库不依赖第三方re正则提取文章链接和内容time请求间隔防止被封三、数据来源分析3.1 搜狗微信搜索的URL规律打开搜狗微信搜索随便搜个词比如小米看地址栏http://weixin.sogou.com/weixin?type2query%E5%B0%8F%E7%B1%B3ieutf8s_frominput_sug_n_sug_type_1参数拆解type2搜索文章type1是搜公众号queryxxx搜索关键词URL编码后的其他参数基本都是固定的可以忽略点下一页地址变成http://weixin.sogou.com/weixin?query%E5%B0%8F%E7%B1%B3page2type2多了个page2这就是翻页参数每页10条结果。3.2 文章链接的定位F12打开开发者工具看Elements面板文章链接都在classtxt-box的div下面divclasstxt-boxh3ahrefhttp://mp.weixin.qq.com/...target_blank文章标题/a/h3/div用正则匹配这个结构提取href就行。3.3 微信文章页面的结构打开一篇微信文章看源码标题在title标签里正文在idjs_content的div里这两个地方就是我们最终要抓的内容。四、代码实现4.1 下载模块先封装一个通用的下载函数后面复用importurllib.requestimporttimeimporturllib.errordefdownloader(url):headers(User-Agent,Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.4793.400 QQBrowser/10.0.702.400)openerurllib.request.build_opener()opener.addheaders[headers]urllib.request.install_opener(opener)try:dataurllib.request.urlopen(url).read()datadata.decode(utf-8)returndataexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)这里用了urllib.request而不是requests主要是想展示一下标准库的用法实际项目中两个都可以。4.2 获取文章链接列表defgetlisturl(key,pagestart,pageend):try:pagepagestart keycodeurllib.request.quote(key)pagecodeurllib.request.quote(page)forpageinrange(pagestart,pageend1):urlhttp://weixin.sogou.com/weixin?type2querykeycodepagecodestr(page)data1downloader(url)listurlpatdiv classtxt-box.*?(http://.*?)data2re.compile(listurlpat,re.S)resultdata2.findall(data1)listurl.append(result)print(共获取到str(len(listurl))页)returnlisturlexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)关键点urllib.request.quote(key)把中文关键词转成URL编码正则里的re.S让.能匹配换行符因为HTML里标签可能换行返回的是二维列表外层是页内层是每页的文章链接4.3 下载并保存文章defgetcontent(listurl):i0# HTML文件头部html1!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd html xmlnshttp://www.w3.org/1999/xhtml head meta http-equivContent-Type contenttext/html; charsetutf-8 / title微信文章页面/title /head bodyfhopen(1.html,wb)fh.write(html1.encode(utf-8))fh.close()fhopen(1.html,ab)foriinrange(0,len(listurl)):forjinrange(0,len(listurl[i])):try:urllisturl[i][j]# 搜狗给的链接里带了amp;得去掉才能正常访问urlurl.replace(amp;,)datadownloader(url)# 提取标题titlepattitle(.*?)/title# 提取正文contentpatidjs_content(.*?)idjs_sg_bartitlere.compile(titlepat).findall(data)contentre.compile(contentpat,re.S).findall(data)if(title![]):thistitletitle[0]if(content![]):thiscontentcontent[0]# 组装成HTML段落写入文件dataallp标题为:thistitle/pp内容为:thiscontent/pbrfh.write(dataall.encode(utf-8))print(第str(i1)个网页第str(j1)条内容保存)excepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)fh.close()# HTML文件尾部html2/body /html fhopen(1.html,ab)fh.write(html2.encode(utf-8))fh.close()这里有几个要注意的地方amp;问题搜狗返回的链接里带了amp;这是HTML实体编码直接访问会404必须replace(amp;, )去掉。正则容错title和content可能匹配不到页面结构变了或者文章被删了所以加了! []的判断。文件模式先用wb写头部再用ab追加内容最后追加尾部。4.4 完整代码importreimporturllib.requestimporttimeimporturllib.errordefdownloader(url):headers(User-Agent,Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.26 Safari/537.36 Core/1.63.4793.400 QQBrowser/10.0.702.400)openerurllib.request.build_opener()opener.addheaders[headers]urllib.request.install_opener(opener)try:dataurllib.request.urlopen(url).read()datadata.decode(utf-8)returndataexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)defgetlisturl(key,pagestart,pageend):try:pagepagestart keycodeurllib.request.quote(key)pagecodeurllib.request.quote(page)forpageinrange(pagestart,pageend1):urlhttp://weixin.sogou.com/weixin?type2querykeycodepagecodestr(page)data1downloader(url)listurlpatdiv classtxt-box.*?(http://.*?)data2re.compile(listurlpat,re.S)resultdata2.findall(data1)listurl.append(result)print(共获取到str(len(listurl))页)returnlisturlexcepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)defgetcontent(listurl):i0html1!DOCTYPE html PUBLIC -//W3C//DTD XHTML 1.0 Transitional//EN http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd html xmlnshttp://www.w3.org/1999/xhtml head meta http-equivContent-Type contenttext/html; charsetutf-8 / title微信文章页面/title /head bodyfhopen(1.html,wb)fh.write(html1.encode(utf-8))fh.close()fhopen(1.html,ab)foriinrange(0,len(listurl)):forjinrange(0,len(listurl[i])):try:urllisturl[i][j]urlurl.replace(amp;,)datadownloader(url)titlepattitle(.*?)/titlecontentpatidjs_content(.*?)idjs_sg_bartitlere.compile(titlepat).findall(data)contentre.compile(contentpat,re.S).findall(data)if(title![]):thistitletitle[0]if(content![]):thiscontentcontent[0]dataallp标题为:thistitle/pp内容为:thiscontent/pbrfh.write(dataall.encode(utf-8))print(第str(i1)个网页第str(j1)条内容保存)excepturllib.error.URLErrorase:ifhasattr(e,code):print(e.code)ifhasattr(e,reason):print(e.reason)time.sleep(10)exceptExceptionase:print(exception:str(e))time.sleep(1)fh.close()html2/body /html fhopen(1.html,ab)fh.write(html2.encode(utf-8))fh.close()if__name____main__:listurllist()keystr(input(请输入要查询的关键词))pagestart1pageendint(input(请输入结束页码(每页保存10条内容)))listurlgetlisturl(key,pagestart,pageend)getcontent(listurl)五、几个容易踩的坑5.1 搜狗反爬搜狗的反爬不算特别严但爬多了也会弹验证码。建议每页之间加time.sleep(1)或更久如果需要大规模采集考虑上代理IP代码里留了代理模块的注释需要的可以放开5.2 微信文章链接失效有些文章可能被删了或者公众号设置了权限打开会提示该内容已被发布者删除。这种情况正则匹配到的内容为空代码里加了! []的判断不会崩但会跳过这篇文章。5.3 正文提取不完整微信文章的正文有时候结构不太统一比如有的带js_sg_bar有的不带。如果抓到的内容少了可以调一下正则表达式或者改用BeautifulSoup解析容错性更好。六、运行效果运行程序后输入关键词和页码请输入要查询的关键词Python 请输入结束页码(每页保存10条内容)3 共获取到3页 第1个网页第1条内容保存 第1个网页第2条内容保存 ... 第3个网页第10条内容保存同级目录下会生成一个1.html用浏览器打开就能看到所有抓取到的文章标题和正文都在里面。