6.3 使用 IP 代理爬取微信文章
6.3.1 分析微信文章的搜索页面及其 URL 的构造特点
爬虫实战-使用代理爬取微信文章
为了增加趣味性,希望爬虫程序可以按照指定搜索的内容及指定的页数下载对应的微信文章。例如,要搜索 Python 相关的文章并希望下载前 10 页,那么爬虫应该可以在运行时接收指令并下载相应页数的文章。下面分析一下微信文章的搜索页面及其 URL 的构造特点。
打开微信文章搜索的页面,如图 6-2 所示。
图 6-2 微信文章的搜索页面
页面上部有一个搜索框,搜索关键字 python,系统返回图 6-3 所示的页面,注意看它的 URL 是如何构造的。
图 6-3 搜索 python 的返回页面
搜索 python 这个关键字的文章列表页面 URL 为 http://weixin.sogou.com/weixin?type=2&query=python&ie=utf8。很显然,搜索结果页面 URL 在 query=后面部分即是搜索的关键词,也就是说,可以在构造 URL 时候,在这里使用不同的搜索关键词,来改变搜索内容。
下面看一下翻页的 URL 是如何构造的。单击下一页,它的 URL 变为 http://weixin.sogou.com/weixin?query=python&type=2&page=2&ie=utf8。也很容易看得出来,这里增加了 page 这一项,用来指定请求的页码,可以换成 page=1,看看第一页是否也满足这个规律。很幸运,第一页满足这一规律。
至此我们已经知道了微信文章搜索的 URL 构造规律,可以通过更改 URL 中 query 项和 page 项的值来构造不同请求内容的不同页面。
因为下载的目标是微信文章,需要进一步分析搜索结果页面中文章的 URL 如何提取出来。在搜索结果页面中,右击一篇文章的题目,在弹出的菜单中选择“检查”,使用 Chrome 浏览器的检查功能,如图 6-4 所示。
图 6-4 使用 Chrome 浏览器的检查功能
从图中可以看出,文章的 URL 就是图中蓝色被选中的这行源码的 href 属性,它的 id 等于 sogou_vr_11002601_title_2。再查看其他文章题目所在的源码,会发现它们的 id 有一个共同的特点,那就是都是以 sogou_vr_11002601_title_开头,后面的数字是文章的序号。因此,我们可以通过 XPath 查询以 sogou_vr_11002601_title_开头的元素,然后取其 href 属性,就得到了文章 URL。最后,直接请求文章 URL 并下载文章内容就可以了。
以上就是对微信文章搜索页面及其 URL 构造特点的分析。
6.3.2 编写爬虫代码
根据上面的分析,爬虫应该包含 4 个部分,也就是说 4 个函数:下载函数 - 用于下载网页;保存函数 - 保存下载的文章;文章 URL 解析函数 - 构造并请求搜索结果网址,然后解析出文章 URL;文章页内容解析函数。
下面从最简单的开始,导入需要的库,编写保存文章的函数。
import requests from lxml import etree import random def data_write(content, title): #保存文章的题目和内容 with open('./wenzhang/' + title.replace('|', '').replace('?', '') + '.txt', 'wt', encoding='utf-8') as f: f.write(content) print('正在下载:', title)
这里准备把每一篇文章保存为一个单独的 txt 文件,这个保存函数有两个参数 - 文章内容和文章标题。用文章标题作为保存文件的文件名,因为文件名中不能包含|和?等符号,为防止个别文章题目中包含这些符号而引起错误,把 title 中的这些符号替换掉。
然后定义一个专门爬取网页、构造选择器的下载函数,这是因为无论是爬取搜索结果页还是下载文章,都要用到爬取网页的动作,所以这里定义一个函数,它的参数就是要爬取的 URL,函数返回页面内容的选择器。
def spider(url): hea = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) \ AppleWebKit/537.36 (KHTML, like Gecko) \ Chrome/46.0.2490.80 Safari/537.36'} #定义代理 IP 列表 Proxies = [ {"http": "http://61.160.6.158:81"}, {"http": "http://122.235.154.46:8118"}, {"http": "http://114.102.38.172:8118"}, {"http": "http://183.147.73.173:8998"}, ] r = requests.get(url, proxies=random.choice(proxies), headers=hea) return etree.HTML(r.text)
这里为了随机使用不同的代理 IP,定义了一个代理 IP 的列表,使用 random.choice 方法,每次请求时随机地取出一个 IP 作为代理。
下面编写构造搜索网址及解析所有文章 URL 的函数 get_all_url。这个函数有两个参数 - 搜索关键字和希望下载的总页数。
def get_all_url(page_nums, keyword): #根据总下载页数循环,构造搜索结果页面的 URL for page_num in range(1, int(page_nums)+1): search_url = 'http://weixin.sogou.com/weixin?query=' + keyword + '&type=2&page = ' + str(page_num)+ '&ie=utf8' selector = spider(search_url) #抓取搜索页 #解析出文章的 URL,使用 yield 作为一个生成器返回 artical_urls = selector.xpath( "//*[starts-with(@id,'sogou_vr_11002601_title_')]/@href") for artical_url in artical_urls: yield artical_url
接下来编写文章内容解析函数。这里作为演示,只简单下载文章的题目和内容。
def spider_xiangqing(wenzhang_url): selector = spider(wenzhang_url) title = selector.xpath ('//h2[@class = "rich_media_title"]/text()')[0].strip() content=selector.xpath( 'string(//*[@class="rich_media_content "])').strip() data_write(content, title)
这里首先获取了文章页面,然后解析出题目和内容,最后使用保存函数保存起来。
最后是主程序,主要就是接收用户的输入内容,然后交给上面定义的函数处理。
if __name__ == '__main__': keyword = input('请输入搜索内容:') page_num = input('请输入下载总页数(必须为自然数 ): ') for article_url in get_all_url(page_num, keyword): spider_detail(article_url)
到这里就完成了整个爬虫的代码编写。为了防止被搜狗反爬虫禁止,这里使用了模拟浏览器的 User Agent 和随机的代理 IP。为了演示,这里只用了 4 个代理 IP。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论