问题

利用爬虫技术能做到哪些很酷很有趣很有用的事情?

回答
爬虫技术是一项强大的数据获取工具,它可以被用来做很多酷炫、有趣且非常有用的事情。下面我将详细阐述一些具体的例子,并说明其实现思路:

酷炫、有趣、有用的爬虫应用

1. 个性化信息聚合与监测

酷炫/有趣的点:
搭建自己的信息中心: 将来自不同网站的最新新闻、技术博客、GitHub Trending项目、B站最新视频、社交媒体热门话题等聚合到一个地方,打造一个属于自己的信息流。
追踪特定对象的动态: 比如你关注某个明星的微博更新、某个公司的新闻发布、某个商品的降价信息,爬虫可以帮你第一时间获取。
监测二手市场价格波动: 实时跟踪你喜欢的数码产品、奢侈品在各大二手平台的价格变化,捕捉最佳购买时机。

有用之处:
高效获取特定领域知识: 对于需要持续学习和了解行业动态的人来说,爬虫是提高效率的利器。
投资决策支持: 监测股票、加密货币、商品期货等信息,辅助投资决策。
市场分析: 抓取竞争对手的产品信息、定价策略、用户评价等,进行市场分析。

实现思路举例(获取B站最新热门视频):

1. 确定目标URL: 找到B站热门视频的页面链接,例如 `https://www.bilibili.com/v/popular/rank/all`。
2. 分析页面结构: 使用浏览器开发者工具(F12)检查页面的HTML结构,找出包含视频标题、链接、封面图、UP主信息、播放量等关键信息的HTML元素(例如 `div`, `a`, `img`, `span` 等标签及其对应的class或id属性)。
3. 选择爬虫框架/库:
Python: `requests`库用于发送HTTP请求获取页面内容,`BeautifulSoup4`或`lxml`库用于解析HTML。
Scrapy框架: 更强大的框架,适用于大规模、高效率的爬取,可以定义Spider来处理爬取逻辑。
4. 编写爬虫代码:
使用`requests.get(url)`获取页面HTML。
使用`BeautifulSoup(html, 'html.parser')`进行解析。
使用`soup.select('css选择器')`或`soup.find_all()`等方法定位到视频列表。
遍历列表中的每个视频,提取标题、URL、UP主、播放量等信息。
5. 数据存储: 将提取到的信息存储到文件(如CSV、JSON)、数据库(如MySQL、PostgreSQL、MongoDB)或者发送到消息队列。
6. 定期执行: 可以使用定时任务工具(如Linux的`cron`、Windows的任务计划程序)或者云服务来定期运行爬虫,实现信息更新。
7. (可选)进一步处理: 可以将视频链接整理成RSS源,或者构建一个简单的网页展示最新的热门视频。

2. 自动化任务与流程处理

酷炫/有趣的点:
自动抢票/秒杀: 在各种限时优惠、演唱会门票、火车票等活动中,用爬虫来“抢”。
自动化注册/信息提交: 自动完成一些需要批量注册、填写信息的流程,例如创建测试账号、参与问卷调查等。
刷流量/点赞(需谨慎,可能违反平台规则): 在某些特定场景下(如测试网站压力),用爬虫模拟用户行为。

有用之处:
提高工作效率: 将重复性的数据录入、信息查询、报告生成等工作自动化。
个性化服务: 为用户提供定制化的信息服务,例如根据用户的偏好推荐商品或内容。
数据验证与校验: 爬取数据并与现有数据进行比对,发现数据不一致之处。

实现思路举例(模拟登陆并自动刷新网页):

1. 分析登陆流程: 通过浏览器开发者工具(Network Tab)分析网站的登陆过程,记录登陆请求的URL、请求方法(POST)、请求头(Headers)中的UserAgent、Cookie等信息,以及提交的表单数据(用户名、密码、验证码等)。
2. 处理Cookie与Session: 登陆成功后,服务器会返回一个Session ID,保存在Cookie中。后续的请求需要携带这个Cookie才能保持登陆状态。`requests`库的`Session`对象可以很好地管理Cookie。
3. 模拟登陆: 使用`requests.Session()`创建一个会话对象,然后发送一个POST请求到登陆接口,带上用户名、密码和必要的头信息。
4. 获取目标数据/执行操作: 登陆成功后,再使用该`Session`对象访问需要登陆才能访问的页面,或者执行其他操作(如提交表单)。
5. 处理验证码: 如果有验证码,需要更高级的技术。
图像识别: 使用第三方验证码识别服务(付费),或者自己训练模型(较复杂)。
OCR识别: 使用光学字符识别(OCR)库(如`pytesseract`)识别图片中的文字。
6. 自动化刷新: 使用定时任务,定期执行登陆和访问页面的操作。

重要提示: 自动化抢票、刷流量等行为可能违反网站的服务条款,甚至涉及法律风险,请务必谨慎使用,并了解相关风险。

3. 数据分析与可视化

酷炫/有趣的点:
社交媒体情感分析: 爬取某个话题下的评论或微博,分析用户的情感倾向(积极、消极、中立),制作情感词云图。
电商评论分析: 抓取商品评论,分析用户关注的优点和缺点,为商家和消费者提供参考。
地图数据可视化: 爬取城市POI(Point of Interest)数据,如餐馆、景点、地铁站等,在地图上进行可视化展示,分析城市布局。
内容趋势分析: 爬取新闻、博客文章等,分析热门关键词、文章长度、发布时间等,揭示内容趋势。

有用之处:
商业智能(BI): 从公开数据中挖掘有价值的信息,辅助商业决策。
学术研究: 收集研究数据,进行统计分析和模型构建。
产品改进: 通过分析用户反馈,发现产品不足之处,进行优化。

实现思路举例(电商商品评论情感分析):

1. 爬取评论: 爬取目标商品页面的所有评论数据,包括评论内容、用户昵称、评论时间等。
2. 数据清洗: 对评论内容进行清洗,去除表情符号、链接、特殊字符、停用词(如“的”、“是”等)等。可以使用`jieba`等中文分词库进行分词。
3. 情感分析:
基于词典的方法: 使用预定义的情感词典(如知网情感词典、BosonNLP情感词典),统计评论中积极词和消极词的数量,计算情感得分。
基于机器学习的方法: 训练一个情感分类模型(如朴素贝叶斯、SVM、深度学习模型),对评论进行分类(正面/负面)。可以使用`sklearn`库或深度学习框架(如`TensorFlow`, `PyTorch`)。
4. 可视化:
情感分布图: 使用`matplotlib`或`seaborn`绘制饼图或柱状图,展示正面、负面、中性评论的比例。
词云图: 使用`wordcloud`库,根据词语的出现频率和情感倾向,生成可视化的词云图,直观展示用户关注的热点。
时间序列分析: 分析情感随时间的变化趋势。

4. 个人知识库与学习辅助

酷炫/有趣的点:
知识图谱构建: 爬取维基百科、知乎等网站,构建特定领域的知识图谱,帮助理解知识之间的关联。
学习资料整理: 爬取特定主题的技术文章、教程、PPT,自动整理成易于查阅的格式。
语言学习助手: 爬取例句、词汇解释、发音链接等,构建个人语言学习库。

有用之处:
深度学习与研究: 快速获取和整理大量文献资料,加速研究进程。
技能提升: 系统地收集和学习某个领域的新知识。
知识管理: 建立个人化的知识体系,方便回顾和应用。

实现思路举例(构建个人技术博客文章库):

1. 确定信息来源: 确定你关注的技术博客或网站,如CSDN、掘金、Medium、个人博客等。
2. 爬取文章列表: 爬取这些网站的文章列表页面,获取每篇文章的标题、URL、作者、发布时间等。
3. 爬取文章详情: 对每个文章URL进行访问,提取文章的正文内容、标签、图片等。
4. 数据清洗与结构化: 清洗文章内容,去除广告、导航栏等无关信息。将文章内容按照标题、作者、正文、标签等字段结构化存储(如Markdown、HTML或数据库)。
5. 建立搜索索引: 使用全文搜索引擎(如Elasticsearch、Whoosh)对爬取到的文章建立索引,方便后续搜索和检索。
6. 自动化更新: 定期运行爬虫,检查是否有新文章发布,并更新到本地库中。
7. 构建前端界面(可选): 开发一个简单的网页应用,用于浏览、搜索和阅读收集到的文章。

5. 辅助编程与开发

酷炫/有趣的点:
API自动化测试: 爬取API文档,自动生成测试用例,提高API测试效率。
代码片段收集: 爬取GitHub Gist、Stack Overflow等网站的代码片段,构建自己的代码库。
文档翻译: 爬取外文技术文档,结合翻译API自动生成中文版本。

有用之处:
提高开发效率: 自动化重复性开发任务,减少手动操作。
知识共享与复用: 方便地查找和使用他人编写的优秀代码。
文档自动化: 减轻编写和维护文档的工作量。

实现思路举例(从Stack Overflow收集特定问题的代码解决方案):

1. 确定搜索关键词: 明确你想解决的编程问题,例如“Python list comprehension examples”。
2. 爬取搜索结果: 爬取Stack Overflow上与关键词相关的搜索结果页面,获取问题标题、链接、回答数量等。
3. 进入问题页面: 访问问题详情页。
4. 识别最佳答案/高分回答: 识别被标记为“Accepted Answer”或获得高分赞同的回答。
5. 提取代码片段: 从回答中提取代码块,通常它们会用特定的HTML标签(如``, `
`)包裹。
6. 存储与分类: 将提取到的代码片段按问题分类存储,并添加相关描述。
7. 构建代码助手: 可以结合IDE插件,实现根据当前代码上下文搜索并插入相关代码片段的功能。

6. 娱乐与创意应用

酷炫/有趣的点:
游戏数据分析: 爬取游戏排行榜、玩家数据、装备属性等,进行数据分析和策略研究。
梗图/表情包收集: 爬取网络上流行的梗图、表情包,构建自己的素材库。
音乐/电影推荐系统: 爬取音乐平台、电影网站的用户评分、评论、标签等信息,分析用户喜好,构建个性化推荐系统。
虚拟世界探索: 爬取游戏内的公开数据或论坛讨论,了解游戏世界观、NPC行为模式等。

有用之处:
提升游戏体验: 通过数据分析优化游戏策略,或者找到有趣的游戏玩法。
内容创作: 为创作提供灵感和素材。
发现新兴趣: 通过个性化推荐发现新的音乐、电影或游戏。

实现思路举例(构建一个网络音乐排行榜展示网站):

1. 确定音乐榜单来源: 选择你喜欢的音乐平台(如网易云音乐、QQ音乐等)的排行榜页面。
2. 爬取榜单信息: 爬取排行榜上的歌曲名称、演唱者、专辑、播放量、歌曲链接(可能需要处理跳转或直接找到可下载链接)。
3. 数据存储: 将爬取到的歌曲信息存储到数据库中。
4. 开发前端展示: 使用Web框架(如Flask、Django、React、Vue.js)开发一个前端页面,查询数据库,展示歌曲排行榜,并提供播放功能(需要处理音频流或跳转到播放平台)。
5. 定期更新: 定时运行爬虫,保持榜单数据的最新。

总结与注意事项

爬虫技术的应用非常广泛,以上只是冰山一角。在进行爬虫开发时,需要注意以下几点:

遵守 robots.txt协议: 大多数网站会有一个`robots.txt`文件,规定了爬虫可以访问的路径和不允许访问的路径。务必遵守这些规则。
尊重网站服务条款: 仔细阅读网站的服务条款,避免进行可能导致封禁或法律纠纷的行为。
控制爬取频率: 过高的爬取频率可能对服务器造成压力,导致IP被封禁。合理设置延时(`time.sleep()`)或使用代理IP池。
处理反爬机制: 很多网站会有各种反爬措施,如验证码、JS加密、IP限制、动态加载内容等。需要针对性地解决,例如使用`Selenium`模拟浏览器行为、识别验证码、使用代理IP等。
数据清洗和处理: 爬取到的原始数据往往是杂乱的,需要进行清洗、去重、格式化等处理才能用于分析和使用。
合法合规: 确保你的爬虫行为符合法律法规,不要爬取受保护的个人隐私信息或用于非法目的。

掌握爬虫技术,意味着你可以更加高效地获取信息,自动化重复性任务,并从中挖掘出有价值的洞察。希望这些详细的例子能激发你的灵感!

网友意见

user avatar

把学校所有重要的在线服务用爬虫集合成了一套JSON API ,然后开发成了App,并且加了一个类似微信朋友圈的功能,可以说是校友圈吧。全校同学和同班同学都可以通过它互相交流,和微信不同的是,同班之间的交流会有消息推送。

App有iOS版和Android版,可以下载并查看教学文档和习题文件,老师有新的通告也会发推送给同学们,还可以查看成绩,课程表,考试时间,个人财务,校园新闻,出勤率等。

目前基本全校都在使用。 一个人开发了两个月。App名字叫MMUBee
开发这个App,我一毛钱都没赚,每年还赔进去四百多美元的开发者注册费和VPS租用费。两个月里也基本上起早贪黑的做。没太多原因,就是喜欢做东西。

我不经常去上课,不过去的时候都可以看见大家在用MMUbee,有一次一个同学打开MMUbee然后对着我说,你快来下载MMUbee,It's awesome!,我说这是我开发的,他没反应过来,过了5秒钟,一脸兴奋的问我Are u kidding me?类似的事情还有很多,比如在上课的时候老师会说,大家不许把考试答案发在MMUbee里。
MMUbee的校友圈里,前两个月90%的Post都是好评。Twitter和Facebook上也都是同学们的一片叫好声,校内论坛更是沸沸扬扬了一段时间。虽然MMUbee本身没有盈利,却给我带来了很多机遇。


查看通告,下载课件,联系导师,点击通告中的日期还可以直接创建提醒:

校内新闻:

校友圈(可以设置查看权限为同班同学或者整个校区):

学生中心(时间表,出勤率,考试时间和成绩等等):

用户评价:




user avatar

谢邀.

2011年夏天我在google实习的时候做了一些Twitter数据相关的开发,之后我看到了一片关于利用twitter上人的心情来预测股市的论文(

battleofthequants.net/w

)。实习结束后我跟几个朋友聊了聊,我就想能不能自己做一点twitter的数据挖掘,当时只是想先写个爬虫玩玩,没想最后开发了两年多,抓取了一千多万用户的400亿条tweet。

上分析篇

先给大家看一些分析结果吧。大家几点睡觉呢? 我们来统计一下sleep这个词在twitter上出现的频率。

看来很多人喜欢在睡前会说一声我睡了。那我们再看一个更有意思的 :"Thursday"这个词的每天出现的频率。

这里2月2号是周四,不出意料,这一天提到周四的频率最高。而且好像离周四越近这个频率越高。可是,为什么2月1号的频率反而低了呢?是因为2月1号大家不说周四而说明天了(有的人会说2月2号也可以说是今天,但是因为在2月2号提到当天的次数太高,因此还是有很多人用周四这个词)。

做了词频统计我们还可以做一些语义分析。我们可以利用unsupervised learning来分析一条tweet的感情色彩。我们对每一条tweet的高兴程度在0至1之间打分,并对每天做平均值,就得到了下面这张图。这里最明显的特征恐怕就是周期性了。是的,大家普遍周末比较高兴。不过这张图的开始和中间有两个点与周期不吻合。如果我告诉你这两天是1月1日和2月14日,那你肯定会想到为什么了,元旦和情人节很多人是很高兴的(不排除slient majority存在的可能)。

这很有意思,但似乎没什么用啊。那我们来看下面这张图,还是2012年的情感分析,不过这里对用户进行了过滤,只保留了来自投资人和交易员的tweet (根据用户的tweet我们可以估计他/她的职业)。蓝线是这些用户的感情色彩,红线是S&P 500指数。看来行情好的时候大家都高兴啊。

最后我们再来看两个统计图吧。2012年是美国大选年,这里统计了在所有和奥巴马相关的tweet里跟提到经济的tweet占的比例。红线是这个比例,黑线是S&P 500

貌似和美国经济有负相关性啊!为什么呢,我们看下面的图就明白了。这个比例和美国失业率正相关,而经济和失业率又是负相关的。换句话说,美国人(尤其是共和党的)找不到工作了就开始埋怨奥巴马了。

除了上面的分析外我做了很多其他的研究,比如如何判断一个用户的职业,验证六度分隔理论, 以及网络扩张速度的建模,不过这里就先不赘述了。

最后要说的是以上的分析在统计上都是不严谨的,twitter上的信息杂音非常大,又有很强的demographic bias,有很多因素都没有考虑。我们只能希望大数定律能过弥补一些误差。写在这里只是抛砖引玉,给大家看一下爬虫可以做什么。大家感兴趣的话之后我可以补充一下这两个话题:

1. 怎样判断一条tweet的感情色彩

2. 怎样估计一个twitter用户的职业

下技术篇

当时Twitter用户大概已经有上亿了,每天新的tweet也有几千万甚至上亿。能不能把这些数据全部抓取下来呢?这是可能的。Twitter是有API的,不过每个IP地址每小时可以抓取150个用户最近的tweet,以这个速度要把几亿个用户抓取一遍需要近一百年。但是,大部分Twitter用户是不活跃甚至从来不发tweet的,还有很多用户是印尼等国家(不是他们不重要,我真的看不懂他们发的tweet),如果我们把不说英语,不发tweet以及follow人数不超过5个(好像注册twitter后用户会被要求follow 5个人)的用户过滤掉,我们就剩下了大约10,000,000个用户,十年就可以搞定了。

十年好像还是太长了。。。不过twitter的访问限制是基于IP地址的,只要我从多个IP访问twitter不久好了(我真的没有DDOS twitter的意思啊)?那么下一步就是搜集大量代理服务器来访问twitter api。为了做twitter的爬虫我专门做了一个爬虫去搜集免费代理服务器。免费的东西总是有代价的,这些服务器非常不稳定。因此我又建立了一套代理服务器管理系统,定期更新IP地址,删除不能用的服务器。最后这套系统平均每天有几百个可用的服务器,大约半个月就可以把一千万个用户抓取一遍了。

此外我又做了一些动态优化,根据twitter用户的follower数量决定他们的抓取频率,以提高重要用户tweet的实时性。

在一年半的时间里,这套系统一共抓取了400亿条tweet,加起来得有10TB,估计占来自美国tweet数量的一半左右。那么问题来了,怎么存贮这些tweet呢?如果要做分析的话恐怕把数据读一遍就要好几天了。很多人马上会说hadoop, cassandra, spark等等。不过作为一个穷学生我哪里有钱去做一个cluster呢?这些数据存在AWS上就得每月1000刀了。

自己动手,丰衣足食。解决方案就是自己组装一个服务器,买了8块3T硬盘做了一个12TB的磁盘矩阵放在寝室里。

软件使用了最为传统的MySQL,这是一个存了400亿条数据的MySQL数据库。我花了大量时间去做优化,尝试了各种各样的partition, ordering, indexing。最后可以实现一天之内对100-200亿条数据进行线型搜索或过滤,或者几秒钟内调取某一天的或某一条tweet。

这台服务器现在留在了MIT,毕业后我把它提供给了一位教授做研究。

PS:

这个项目在2013年停止了,因为social media已经不在火,而且twitter于2013年中关闭了相关的API接口。

这个项目的初衷是学术性质的,我不想违反twitter的服务条款,因此这些数据没有被出售或者用来谋求商业价值,而是留给了MIT做研究。

在这期间与几个朋友进行了很愉快的合作,未征得他们允许就不在此提名了。

暂时没有开源的打算,因为当时水平有限,代码写得太丑了(用java写的)。

PS2:

很多人问怎么找代理服务器,请大家google一下吧。当然如果不能翻墙的话有代理服务器恐怕也不能用。

谢绝转载。

user avatar
彩蛋:

彩蛋已关闭

骚瑞

为后来的同学解释一下彩蛋怎么回事,顺便对昨晚12点之后收不到彩蛋的同学抱歉(鞠躬),被屏蔽了

  • 彩蛋是如果赞了这条答案会自动收到一条随机的私信,里面是一则短笑话
  • 笑话是在某网站上爬下来的,一共几十条随机发送

起因是昨天写完原答案,突然想到如果加上彩蛋会不会很多人点赞(说我不是骗赞自己也不信)

于是写了个小脚本,跑了起来试了一下

第一次高潮出现在回答完30分钟后,突然多了一两百的赞,由于私信发送时间间隔太短,挂掉了

修复后坚持到了晚上十二点,本机和VPS都不能再持续发送私信,于是停掉了

今早起来发现赞又多了3000,崩溃的我决定还是不接着发了。。。

代码和逻辑如下:

       // 代码不全,只有主要的逻辑 // 用到的库如下:  var request = require('superagent'); var cheerio = require('cheerio'); var fs = require('fs');  // 首先是这样的一个接口,可以取到某个答案所有赞同的人数 // 每次取会返回10条数据,是编译好的HTML模版,还有下一组数据的地址 // 遍历这10条数据并取到所有人的ID即可 // config 是Cookie、Host、Referer等配置  var sourceLink = 'https://www.zhihu.com/answer/' + code + '/voters_profile';  function getVoterList(link, fn) { var next = ''; if (postListLength && !sleepIng) { console.log('waiting'); sleepIng = true; return setTimeout(function () { sleepIng = false; sleep = 1; getVoterList(link, fn); }, 1000 * 60); } request.get(link) .set(config) .end(function (err, res) { if (err || !res.ok) { return console.log(err); } var result = JSON.parse(res.text), voterList = '', $;  if (result.paging && result.paging.next) { next = result.paging.next; }  if (result.payload && result.payload.length) { voterList = result.payload.join(''); $ = cheerio.load(voterList);  $('.zm-rich-follow-btn').each(function () { var id = $(this).attr('data-id');  if (voterIdList.indexOf(id) === -1 && oldIdList.indexOf(id) === -1) { console.log('new id: ', id); voterIdList.push(id); } else { dupIdLen += 1; } }); }  if (next && dupIdLen < 20) { setTimeout(function () { getVoterList('https://www.zhihu.com' + next, fn); }, 3000); } else { dupIdLen = 0; fn(); } }); }  // 在爬取完该接口后,新的点赞人数会暂存在数组中,遍历该数组,并发送请求 // 如请求发送成功,将各ID保存在某一个文件中,如发送失败,等几分钟后重试  function sendPost() { var hasError = false; var tempArr = []; postListLength = voterIdList.length; console.log('send post');  if (voterIdList.length) { voterIdList.forEach(function (id, i) {  if (hasError) { // 处理发送失败的情况,等待5分钟重试 if (!sleepIng) { console.log('waiting'); sleepIng = true; return setTimeout(function () { sleepIng = false; sleep = 1; sendPost(); }, 1000 * 60 * 5); }  return console.log('has error'); }  var index = (function () { return i; })(i); var postIndex = index > postList.length ? index % postList.length : index;  setTimeout(function () { // 一波发送完成之前不会启动下一波私信发送 postListLength--; request.post('https://www.zhihu.com/inbox/post') .send({ member_id: id, content: postList[postIndex], token: '', _xsrf: '' // 这里是发送者的Cookie }) .set(config) .set({"Accept": "*/*"}) .set({"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"}) .end(function (err, res) { console.log('hasError: ', hasError); console.log(new Date()); console.log(res.text); var resObj = {};  try { resObj = JSON.parse(res.text); } catch (e) { console.log(e);  if (!sleepIng) { hasError = true; sleep = 5; console.log('waiting'); sleepIng = true; return setTimeout(function () { sleepIng = false; sleep = 1; sendPost(); }, 1000 * 60 * 5); } }  if (err || !res.ok || resObj.r !== 0) { console.log(err); hasError = true; sleep = 5; tempArr = voterIdList.slice(0, index); oldIdList = oldIdList.concat(tempArr); fs.writeFile('./idlist.json', oldIdList, function (err) { if (err) console.log(err); }); } }); }, 20 * 1000 * index * sleep);  if (index === voterIdList.length - 1) { console.log('last'); oldIdList = oldIdList.concat(voterIdList); voterIdList = []; setTimeout(function () { console.log('run again'); getVoterList(sourceLink, sendPost); }, 1000 * 60 * 15);  fs.writeFile('./idlist.json', oldIdList, function (err) { if (err) console.log(err); });  console.log('done '); } }); } else { setTimeout(function () { console.log('run again'); getVoterList(sourceLink, sendPost); }, 1000 * 60); } }      

代码花了半个小时写的,比较糙,不过跑了一下确实能用,既然已经不发了就不改了,有同学要求就发上来了

PS 知乎的策略应该有变化,昨晚12点之前只要对同一个人两条私信不重复,把握好发送时间间隔就没问题,12点之后我的VPS已经不能用了,时间间隔再久也会返回500错误,1点后我的本机也不行了,不断的返回500和403,Cookie也有更新,索性就停掉了

这是昨晚爬到的ID


还有我的视角所看的我的私信列表= =


就酱


==============================

某人有一天书荒了,想要看豆瓣上的高分书,然而豆瓣并没有提供按评分的检索,于是拜托我写一个小东西,要求是能按现有标签来分类检索豆瓣图书,并按分数从高到低排序

需求不难,就是数据没有,于是写了个爬虫按标签爬下来豆瓣所有的书

爬的时候只爬了分类的列表,这样有书籍的名称,链接,评分,分类,够用了,而且一次请求可以拿到较多的数据,并发不高的情况下能较快的爬完豆瓣所有的书

爬数据的时间大概两个多小时左右,每次请求间隔3秒,倒是没被屏蔽

代码用node写的,包括外网访问的服务器,基本满足了某人的需要,现在跑在我自己的VPS上,有域名可以直接访问

爬完知道豆瓣热门标签下大概有6万多本书,是会不断更新的,所以还要定期爬一下更新一下数据

下面是预览,时间所限页面写的糙了点,反正用户就一个- -



user avatar

没想到得到这么多赞,有点小害怕啊~有一些问题我在下面回答以下把。

------------------------------------------------正常分割线----------------------------------------------------

2011年,我还在学校读书,写了个软件注册了几十万个新浪微博账号。(那时候还不要求实名制,真怀念)。然后就要养账号,写了几个爬虫软件从搜狐微博上爬昵称用来更新我新浪微博上的昵称,从大V的粉丝中爬他们的头像用来更新自己的微博头像(我对不起大家!),从笑话微博中爬微博内容来发到自己微博中。用这这几十万个微博账号去参与抽奖,一年获利了七万多块钱。读书那几年我承包了我们宿舍所有的水电费和我们班男生宵夜啤酒鸭霸王的费用。

------------------------------------------问题回答--------------------------------------------------------------

1、是不是用Python写的,用别的语言可以实现不啦?

答:是用C#写的,Python没有学过,毕竟专业不是计算机,毕业后所从事的工作也不是程序员,所以没有学习这个的动力。别的语言肯定也是可以实现的,计算机语言之间都有相似性,只是实现起来的难易程度不一样。上学时学习C#完全是出于爱好,在学习、工作上能够解决自己的问题即可。我不适合专职做程序员,去理解别人的需求很痛苦,其实曾经尝试着去当一名伟大的软件程序员来着,可惜北漂未遂。

2、怎么知道你的帐号中奖了?

答:我自己的帐号我一眼就能认得出来。我一般用一个大号去参加抽奖(大号一般不会被封),然后用软件去监测我的大号参与抽奖。这样我的小号转发的有奖活动跟我的大号之间就几乎相同了(为什么说几乎,因为有部分会失败)。活动开奖后,我只要从我的大号中进入抽奖页面查看中奖帐号即可。我自己的帐号全部申请了10个左右的勋章,有昵称、有头像、有学校、有年龄、有标签,最重要的是从所转发的微博和抽奖活动来看,一个有奖活动中间夹杂几个正常微博,正常微博的内容我是从谁的微博中抓取的我也都能认识。只要疑似自己的帐号,把它的UID或者nickname放入数据中中检索便知结果。

3、新浪微博不封号?

答:肯定封,而且经常好几千上万那样封。所以我一次性都是用一万个左右的帐号去参加抽奖,封掉了就用下一批。此外换IP是常识,之前十个左右换一个IP,后来严格了,基本上三五个就换一次IP。封号和反封号跟新浪也是斗智斗勇,每次帐号被封之后我都会把同一批使用但幸存的那么几百个帐号来进行分析。同批次参与活动为什么大部分帐号被封,但是还有几百个幸存的呢,他们之间肯定是有差异的,找到这种差异去猜测新浪技术然后改进我的软件。

4、现在还做不做这方面的软件了,不做可惜了,能不能帮我写个某某软件,批量生成一些知乎点赞帐号和点赞软件?

答:现在不做,从来都没有想过把这个当作所谓的事业。现在有了正经工作,而且收入也比做这个要多,为什么还要去做这种边缘性的东西。

5、鸭霸王是什么?

答:下酒菜,湖南特色,辣的够滋味,毕业了怀念。

6、碉堡?

答:会很疼,还是不要。

user avatar

死宅一枚。爬取5000张二次元妹子的图片,生成了下面这张图(查看原图小图清晰可见,没有奇奇怪怪的图片)。

上手难度低,适合新手。


具体制作流程:

  • 使用 Scrapy 框架爬取5000张二次元图片
  • 使用 Pillow 批量格式化图片
  • 将图片按照 HSV 的欧式距离排序重新组合图片,实现效果
  • 或者借助软件类似 Foto-Mosaik-Edda 实现相同效果



合成软件下载地址:Welcome | FMEdda | Foto-Mosaik-Edda

Github项目地址 https://github.com/ThomasHuai/puzzle


为了彰显社会主义核心价值观,请各位在使用爬虫的时候遵守网站robots.txt中的爬虫协议,图片以个人收集为目的,不要占用站长大量带宽。

一、安装开发环境


  1. 安装 Scrapy 爬虫框架
       pip install Scrapy     


windows 安装可以点击此处


2.安装 numpy 科学计算库

       pip install numpy     


3. 初始化一个 Scrapy 项目 acg

       scrapy startproject acg     


  • 2018年4月10日优化后不再使用openCV(各别同学反映太难安装),改用Pillow,效果一样。

二、爬取图片

2018年4月20日更新内容

  • 修复抓取路径到 2018-4-20 可用
  • 使用 ImagesPipeline 下载图片
  • 抓取时不处理图片(对应一些人想要原图的要求)

爬取详细

  • 图片默认存储路径是 database/full 文件夹,图片名为hash值
  • 自定义路径请在 setting.py 中进行修改
  • 自定义文件名请在 pipelines.py 中重构 ImagesPipeline 类


       #coding=utf-8 #update at 2018-4-20 from acg.items import ImageItem import scrapy import numpy as np import os  class acgimages(scrapy.Spider):  """docstring for acgimages"""  name = 'images'  start_urls = [   "http://www.acg.fi/anime/page/1"  ]  page = 1  count = 0  MAX_CATCH_PAGES = 1000  item = ImageItem()  def parse(self,response):   next_page = response.xpath('//div[@class="grid-bor"]//a/@href').re(r'http://www.acg.fi/anime/([0-9]+).htm')   used = []   for page in next_page:    if page not in used:     used.append(page)   print('find %d secound pages' % len(used))   for number in used:    url = "http://www.acg.fi/anime/%s.htm" % number    self.item['url'] = url    yield scrapy.Request(url, callback = self.post_page)    if self.page < self.MAX_CATCH_PAGES:    self.page = self.page + 1   next_url = "http://www.acg.fi/anime/page/%d" % self.page   yield scrapy.Request(next_url, callback = self.parse)   def post_page(self,response):   images_url = response.xpath("//div[@id='entry-content']//img/@src").extract()   print('find %d images' % len(images_url))   self.item['images'] = images_url   return self.item     

三、生成图片


软件下载地址:Welcome | FMEdda | Foto-Mosaik-Edda


1.创建一个图片数据库

2.导入图片

3.导入过程中

4.创建一个马赛克风格图片

5.打开原图

6.选择已经上传的数据库



7.生成完成

简单高效的平民玩法到此结束。


逼格不够?

下面分享用 python 代码实现该软件的马赛克拼图效果。


一、安装依赖


1.安装图像处理库 pillow


       pip install pillow     


二、使用 Python 做到马赛克拼图效果


1.使用 hsv (颜色空间)完成颜色精准适配

2.自定义图片重复数量

3.增加命令行进度条,增加命令行可自定义参数

4.创建完成拼图数据库后可以直接合成,不用重复执行创建

5.多线程处理图片提高效率


hsv (颜色空间模型)



hsv 两点间距离公式(欧式距离):


/main.py

       import os from PIL import Image,ImageOps import argparse import time from multiprocessing import Pool import random import math import sys from colorsys import rgb_to_hsv  SLICE_SIZE = 85 OUT_SIZE = 5000 IN_DIR = "database/full/" OUT_DIR = "output/" REPATE = 0  def get_avg_color(img):     width, height = img.size     pixels = img.load()     if type(pixels) is not int:         data = []         for x in range(width):             for y in range(height):                 cpixel = pixels[x, y]                 data.append(cpixel)         h = 0         s = 0         v = 0         count = 0         for x in range(len(data)):             r = data[x][0]             g = data[x][1]             b = data[x][2]             count += 1             hsv = rgb_to_hsv(r / 255.0,g / 255.0,b / 255.0)             h += hsv[0]             s += hsv[1]             v += hsv[2]          hAvg = round(h / count,3)         sAvg = round(s / count,3)         vAvg = round(v / count,3)          if count > 0:              return (hAvg,sAvg,vAvg)         else:             raise IOError("读取图片数据失败")     else:         raise IOError("PIL 读取图片数据失败")   def find_closiest(color, list_colors):     diff = 1000     cur_closer = False     arr_len = 0     for cur_color in list_colors:         n_diff = math.sqrt(math.pow(math.fabs(color[0]-cur_color[0]), 2) + math.pow(math.fabs(color[1]-cur_color[1]), 2) + math.pow(math.fabs(color[2]-cur_color[2]), 2))         if n_diff < diff and cur_color[3] <= REPATE:             diff = n_diff             cur_closer = cur_color     if not cur_closer:         raise ValueError("没有足够的近似图片,建议设置重复")     cur_closer[3] += 1     return "({}, {}, {})".format(cur_closer[0],cur_closer[1],cur_closer[2])   def make_puzzle(img, color_list):     width, height = img.size     print("Width = {}, Height = {}".format(width,height))     background = Image.new('RGB', img.size, (255,255,255))     total_images = math.floor((width * height) / (SLICE_SIZE * SLICE_SIZE))     now_images = 0     for y1 in range(0, height, SLICE_SIZE):         for x1 in range(0, width, SLICE_SIZE):             try:                 y2 = y1 + SLICE_SIZE                 x2 = x1 + SLICE_SIZE                 new_img = img.crop((x1, y1, x2, y2))                 color = get_avg_color(new_img)                 close_img_name = find_closiest(color, color_list)                 close_img_name = OUT_DIR + str(close_img_name) + '.jpg'                 paste_img = Image.open(close_img_name)                 now_images += 1                 now_done = math.floor((now_images / total_images) * 100)                 r = '
[{}{}]{}%'.format("#"*now_done," " * (100 - now_done),now_done)                 sys.stdout.write(r)                                           sys.stdout.flush()                     background.paste(paste_img, (x1, y1))             except IOError:                 print('创建马赛克块失败')     return background   def get_image_paths():     paths = []     for file_ in os.listdir(IN_DIR):         paths.append(IN_DIR + file_)     if len(paths) > 0:         print("一共找到了%s" % len(paths) + "张图片")     else:         raise IOError("未找到任何图片")      return paths   def resize_pic(in_name,size):     img = Image.open(in_name)     img = ImageOps.fit(img, (size, size), Image.ANTIALIAS)     return img  def convert_image(path):     try:         img = resize_pic(path,SLICE_SIZE)         color = get_avg_color(img)         img.save(str(OUT_DIR) + str(color) + ".jpg")     except IOError:         print('图片处理失败')  def convert_all_images():     paths = get_image_paths()     print("正在生成马赛克块...")      pool = Pool()     pool.map(convert_image, paths)     pool.close()     pool.join()     def read_img_db():     img_db = []     for file_ in os.listdir(OUT_DIR):         if file_ == 'None.jpg':             pass         else:                  file_ = file_.split('.jpg')[0]             file_ = file_[1:-1].split(',')             file_ = list(map(float,file_))             file_.append(0)             print(file_)             img_db.append(file_)         return img_db  if __name__ == '__main__':      parse = argparse.ArgumentParser()     parse.add_argument("-i",'--input',required=True,help='input image')     parse.add_argument("-d", "--db", type=str, required=True,help="source database")     parse.add_argument("-o", "--output", type=str, required=True,help="out directory")     parse.add_argument("-s","--save",type=str,required=False,help="create image but not create database")     parse.add_argument("-is",'--inputSize',type=str, required=False,help="inputSize")     parse.add_argument("-os",'--outputSize',type=str, required=False,help="outputSize")     parse.add_argument("-r",'--repate',type=int, required=False,help="repate number")     args = parse.parse_args()     start_time = time.time()     args = parse.parse_args()     image = args.input      if args.db:         IN_DIR = args.db     if args.output:         OUT_DIR= args.output     if args.inputSize:         SLICE_SIZE = args.inputSize     if args.outputSize:         OUT_SIZE = args.outputSize     if not args.save:         convert_all_images()     if args.repate:         REPATE = args.repate      img = resize_pic(image,OUT_SIZE)     list_of_imgs = read_img_db()     out = make_puzzle(img, list_of_imgs)     img = Image.blend(out, img, 0.5)     img.save('out.jpg')      print("耗时: %s" % (time.time() - start_time))     print("已完成")       


命令行

  • -s -- save 已经存在output文件夹已经有马赛克图片,快速生成图片
  • -i -- input 原始图片路径
  • -d -- database 爬虫图片数据集
  • -o -- output 马赛克图标生成路径
  • -is -os 输入(马赛克块)/ 输出(生成图) 图片尺寸
  • -r --repate(int) 重复(建议在图片集少的时候设置


       python puzzle.py -i test.jpg -d database/full/ -o output/      


上传一张5000张不重复结果图



已知问题

  • 少数图片,图片后缀名错误,比如说jpg图片修改后缀名为png进行伪造将会影响 Pillow 读取像素信息。(4-20 更新已经跳过影响图片)
  • 效果较差的原因有可能是,图片集数量不够(建议5000之内设置重复),黑白构图图片太多会直接影响 hsv 结果,图片单一,无法就近匹配。
  • 更多优化建议,bug信息请在评论区回复,感谢支持。


原创不易,欢迎点赞。

四斋蒸鹅心。


那么。数据爬虫帮你搞定了,还不赶紧趁热来一发数据挖掘或者机器学习?

欢迎关注后续文章。


---------------------- 分割线 -----------------------

2019.10.21

看看我发现了什么。。。



Github项目地址

参考文档:

类似的话题

  • 回答
    爬虫技术是一项强大的数据获取工具,它可以被用来做很多酷炫、有趣且非常有用的事情。下面我将详细阐述一些具体的例子,并说明其实现思路: 酷炫、有趣、有用的爬虫应用 1. 个性化信息聚合与监测酷炫/有趣的点: 搭建自己的信息中心: 将来自不同网站的最新新闻、技术博客、GitHub Trending项目.............
  • 回答
    好的,咱们就来聊聊怎么用 Twitter 的开放者平台,正经八本地“摸”点数据出来。这玩意儿玩好了,信息量可大了去了,不过也得注意着点规矩,别被人家给“封了”。说白了,Twitter 开放者平台就像是 Twitter 提供给你的一扇大门,让你能合法地访问它上面的各种信息。你想发个推,想看点别人推,想.............
  • 回答
    战舰世界亚服0.9.2的爬坑环境以及强势线路分析舰长们大家好!我是你们的老朋友,今天咱们来聊聊亚服在0.9.2版本下的爬坑选择和当前的大环境。0.9.2版本更新至今已经有一段时间了,各国的科技树和玩法也逐渐趋于稳定,那么在这个版本里,哪些线路是更容易让我们在排位和匹配中顺利“上分”的呢?同时,当前亚.............
  • 回答
    利用碎片时间能否学到新知识?这真是个太值得探讨的问题了!我觉得答案是肯定的,而且我身边就有不少例子证明了这一点。不过,这事儿也不是说你想就能做到的,里面有不少门道。首先得明白,“碎片时间”到底是个什么概念。它不是你正襟危坐、关掉所有干扰、专心致志看书的“大块时间”。它是你在通勤路上、排队等餐、午休间.............
  • 回答
    用“不可思议”的数字给你的数据瘦身?关于无理数压缩的畅想我们每个人手机里、电脑里都塞满了各种各样的文件:照片、视频、音乐、文档……这些数字信息庞大得惊人,总是让我们在“空间不足”和“删除不舍”之间纠结。于是,我们想方设法地压缩这些数据,让它们更小巧,更易于存储和传输。大家熟悉的ZIP、RAR、JPE.............
  • 回答
    用1V的正弦交流电源产生大电压,并且利用这个大电压,这是完全可行的,关键在于利用“谐振”这个物理现象。很多人一听“谐振”就觉得是无线电或者高科技的东西,其实它原理很基础,就像你推秋千一样,找准时机用力,秋千就能越荡越高。谐振是如何“放大”电压的?想象一下,我们有一个很简单的电路,它包含一个电感(L).............
  • 回答
    利用放大镜,我们可以探索许多有趣而富有启发性的科学实验,这些实验不仅能让我们观察到微观世界的奇妙,还能帮助我们理解一些基础的物理学原理。以下是一些利用放大镜可以做的有意思的实验,我将尽量详细地讲述: 一、 光的聚焦与能量传递实验核心原理: 放大镜属于凸透镜,可以将平行光线汇聚于一点,形成一个焦点。这.............
  • 回答
    福岛核泄漏事故发生后,确实有人提出过是否能用氢弹来处理的设想。这听起来确实像是一个“一劳永逸”的解决方案,用强大的力量来瞬间压制住失控的核反应堆。但实际上,我们深入探讨一下就会明白,这个想法在现实中是极其不切实际,甚至可以说是灾难性的。为什么会有这样的想法?氢弹,也叫热核武器,其威力来自于氢的同位素.............
  • 回答
    “非天然核苷酸”的“半合成生命体”:一扇通往无限应用可能的大门设想一下,我们不再局限于生命自身演化的轨迹,而是能够主动地在基因组中引入全新的“乐高积木”,构建出前所未有的生命形式。这便是“非天然核苷酸”(Unnatural Nucleotides)与“半合成生命体”(Semisynthetic Or.............
  • 回答
    酿酒过程中,我们利用酵母菌进行无氧呼吸,这个过程是否算“剥削”了酵母菌的剩余价值?这个问题,如果抛开那些生硬的科学术语,用更贴近生活的语言去聊,其实挺有意思的。我觉得与其说是“剥削”,不如说是一种“互利共生”,只不过在其中人类扮演了更主动、更具目的性的角色。我们先来看看酵母菌在酿酒这个“工作”里扮演.............
  • 回答
    当然,我们可以探讨利用现代技术来“固定”一颗小行星的可能性。这并非简单的物理束缚,而更像是一种复杂的“轨道控制”和“位置维持”。想象一下,我们不是在用链条拴住它,而是用一种更巧妙、更具动态性的方式,让它待在我们希望它待的地方。核心挑战与思路:首先,我们要明白,小行星本身在太空中拥有巨大的动能和惯性。.............
  • 回答
    京沪铁路济南泰安段改造市域铁路可行性分析京沪铁路作为中国最繁忙的铁路线之一,其济南至泰安段的既有线路,在承担长途客运和货运任务的同时,也为区域经济发展贡献了重要力量。然而,随着济南都市圈和泰安市经济社会发展的加速,以及城镇化进程的不断推进,这条线路在满足日益增长的区域交通需求方面,正面临新的挑战。在.............
  • 回答
    “永动机”的概念,一个吸引了无数梦想家和科学家的古老神话,在科幻作品和坊间传说中经久不衰。而“无工质引擎”——即不需要消耗任何介质或燃料就能产生动力的装置,正是这个概念在现代技术语境下的一个分支。人们不禁好奇,能否利用纯粹的热辐射来构建这样的引擎?从物理学的基本原理出发,这个问题涉及到热力学定律,尤.............
  • 回答
    晚上房价一夜之间跌到1000元/平方米,而且所有人都能随便买三四套,第二天早上又猛地涨回34万元/平方米,这简直是科幻小说里的情节,要是真发生了,那世界估计会乱成一锅粥,绝对是场灾难性的事件。首先,我们得想想这“一夜跌价”是怎么发生的。这肯定不是什么正常的市场调整,而是有人或者某种力量在背后操控,而.............
  • 回答
    夜景摄影,尤其是用单反拍摄,是一门关于耐心、技巧和对光线深刻理解的艺术。它不像白天的阳光那样直观,而是需要我们去捕捉和引导那些隐藏在黑暗中的美。下面我将为你详细讲解,如何用单反拍出令人惊艳的夜景照片,力求让你感受到其中每一个细节的操作和思考。一、 了解你的装备:单反不仅仅是相机首先,你需要明白,你的.............
  • 回答
    将α射线反冲作为深空发动机的动力源,这绝对是个引人入胜的设想,也触及到了物理学中最根本的原理之一。要详细探讨它的可行性,我们得深入剖析其背后的物理机制、潜在的优势劣势,以及在工程实现上会遇到的巨大挑战。首先,我们得明白什么是α射线反冲。简单来说,α射线是氦原子核,也就是由两个质子和两个中子组成的粒子.............
  • 回答
    这个问题问得很有意思,触及到了微积分理论和实际应用的核心。简而言之,利用微分法(这里应该是指通过求导的逆运算,即求不定积分,然后再代入上下限来计算定积分)计算出的结果,在数学理论上是绝对真实的,是我们定义和理解定积分的精确方法。但是,要深入理解这一点,我们需要把“利用微分法计算定积分”这个说法拆解开.............
  • 回答
    利用性别因素和私人关系,主要依靠他人力量进行学术发表,这确实触及了学术诚信的红线,并且在很大程度上可以被界定为学术不端行为。为了更清晰地理解这一点,我们需要从几个层面来剖析。首先,我们来解析一下“依靠他人力量进行学术发表”本身。学术研究和发表的根本在于研究者个人的思考、探索、实验、分析和写作能力。一.............
  • 回答
    关于曹原在石墨烯超导领域的研究,为什么没能获得2018年的诺贝尔奖,这个问题其实触及到了科学发现、诺贝尔奖评选机制以及科学界对新事物的认知和验证过程的方方面面。要详细解释,我们需要从几个关键点入手:1. 诺贝尔奖的评审标准与周期:诺贝尔奖,尤其是物理学奖,非常看重“经过时间检验”的、“具有划时代意义.............
  • 回答
    八天时间,在泳池里自学学会游泳,这事儿,能不能成?说实话,这事儿吧,挺悬的,但也不是完全没可能。关键看你自己的悟性、身体协调性,还有最重要的——你愿意在这八天里付出多少努力。我得先跟你打个预防针,不是人人都能在这么短的时间里“学会”游泳。所谓“学会”,咱们得有个标准。如果你指的是能像条鱼一样自由自在.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有