有话要说:

这次准备讲述用python爬虫以及将爬来的数据存到MySQL数据库的过程,爬的是煎蛋网的无聊图。

成果:

准备:

  1. 下载了python3.7并配置好了环境变量
  2. 下载了PyCharm作为开发python的IDE
  3. 安装了MySQL客户端以及服务端
  4. 安装了Navicat客户端
  5. 通过pip命令下载安装beautifulsoup,selenium以及pymysql模块,pip命令如下:
pip install beautifulsoup4
pip install selenium
pip install pymysql

观察“无聊图”网页源码:

先上部分源码:

 <li id="comment-3838846">
<div>
<div class="row">
<div class="author"><strong
title="防伪码:fc33b015c2b4d50cd1a23007810b09f049f1407d" class="orange-name">猴子</strong> <br>
<small><a href="#footer" title="@回复"
onclick="document.getElementById('comment').value += '@&lt;a href=&quot;//jandan.net/pic/page-185#comment-3838846&quot;&gt;猴子&lt;/a&gt;: '">@4 days ago</a></span></small>
</div>
<div class="text"><span class="righttext"><a href="//jandan.net/pic/page-185#comment-3838846">3838846</a></span><p>这个盖字是怎么翻译出来的<br />
<img src="//img.jandan.net/img/blank.gif" onload="jandan_load_img(this)" /><span class="img-hash">Ly93dzMuc2luYWltZy5jbi9tdzYwMC8wMDZYTkVZN2d5MWZydm84MHg0Mm1qMzFrdzIzdmF6cS5qcGc=</span></p>
</div>
<div class="jandan-vote">
<span class="comment-report-c">
<a title="投诉" href="javascript:;" class="comment-report" data-id="3838846">[投诉]</a>
</span>
<span class="tucao-like-container">
<a title="圈圈/支持" href="javascript:;" class="comment-like like" data-id="3838846" data-type="pos">OO</a> [<span>52</span>]
</span>
<span class="tucao-unlike-container">
<a title="叉叉/反对" href="javascript:;" class="comment-unlike unlike" data-id="3838846" data-type="neg">XX</a> [<span>13</span>] <a href="javascript:;" class="tucao-btn" data-id="3838846"> 吐槽 [16] </a>
</span>
</div>
</div>
</div>
</li>

发现在源码里边图片链接并没有直接显示出来,而是在js中加载的。因此,不能用普通的爬虫方式来获取图片链接。

看了许多博客,最终决定采用Python3+BeautifulSoup+selenium的方式来抓取。

selenium用来获取网页链接数据,BeautifulSoup用来解析获取的网页源码。

selenium相当于一个小型浏览器,可以直接获取完整的网页源码,获取之后的网页源码如下所示:

 <li id="comment-3838846">
<div>
<div class="row">
<div class="author"><strong title="防伪码:fc33b015c2b4d50cd1a23007810b09f049f1407d" class="orange-name">猴子</strong> <br>
<small><a href="#footer" title="@回复" onclick="document.getElementById('comment').value += '@<a href=&quot;//jandan.net/pic/page-185#comment-3838846&quot;>猴子</a>: '">@4 days ago</a></small>
</div>
<div class="text"><span class="righttext"><a href="//jandan.net/pic/page-185#comment-3838846">3838846</a></span><p>这个盖字是怎么翻译出来的<br>
<a href="//ww3.sinaimg.cn/large/006XNEY7gy1frvo80x42mj31kw23vazq.jpg" target="_blank" class="view_img_link">[查看原图]</a><br><img src="http://ww3.sinaimg.cn/mw600/006XNEY7gy1frvo80x42mj31kw23vazq.jpg" style="max-width: 100%; max-height: 450px;"></p>
</div>
<div class="jandan-vote">
<span class="comment-report-c">
<a title="投诉" href="javascript:;" class="comment-report" data-id="3838846">[投诉]</a>
</span>
<span class="tucao-like-container">
<a title="圈圈/支持" href="javascript:;" class="comment-like like" data-id="3838846" data-type="pos">OO</a> [<span>52</span>]
</span>
<span class="tucao-unlike-container">
<a title="叉叉/反对" href="javascript:;" class="comment-unlike unlike" data-id="3838846" data-type="neg">XX</a> [<span>13</span>] <a href="javascript:;" class="tucao-btn" data-id="3838846"> 吐槽 [16] </a>
</span>
</div>
</div>
</div>
</li>

注意到,class="row"的div是我们需要的,并且不包含我们不需要的部分,因此就可以通过class="row"来获取需要的数据。

又因为一条段子包含的信息有:一个标题(有些有有些没有),若干张图片,点赞数,点踩数。因此设计数据库表如下:

数据库表设计:

因为以上的信息,故设计了两张表。

一张表用来存放段子的基本信息,包括主键、标题、点赞数、点踩数;

另一张表用来存放段子包含的图片链接,包括主键、图片链接、段子主键。

用段子主键来相互关联,主要SQL语句如下:

CREATE TABLE `news` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '段子标识',
`title` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '段子标题',
`like` int(11) DEFAULT NULL COMMENT '点赞数',
`unlike` int(11) DEFAULT NULL COMMENT '点踩数',
PRIMARY KEY (`id`)
) CREATE TABLE `news_pics` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '图片标识',
`url` varchar(255) DEFAULT NULL COMMENT '图片链接',
`newsid` int(11) NOT NULL COMMENT '段子标识',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=319 DEFAULT CHARSET=utf8;

主体部分:

接着,阅读了Python爬取煎蛋妹子图以及python+selenium+PhantomJS爬取网页动态加载内容之后,实现了利用python进行抓取数据解析数据的过程,先上代码:

 # coding=utf-8
import re
import pymysql
from bs4 import BeautifulSoup
from selenium import webdriver base_url = "http://jandan.net/pic/page-"
driver = webdriver.PhantomJS() items = []
urls = ["http://jandan.net/pic/page-{}#comments".format(str(i)) for i in range(50689352, 50689355)] db = pymysql.connect(host="localhost", user="root", password="root", db="imitating9gag", charset="utf8")
cursor = db.cursor() sql_news = '''INSERT INTO `imitating9gag`.`news` (`id`, `title`, `like`, `unlike`) VALUES ('%d', '%s', '%d', '%d')'''
sql_pics = '''INSERT INTO `imitating9gag`.`news_pics` (`id`, `url`, `newsid`) VALUES ('%d', '%s', '%d')''' if __name__ == "__main__":
for url in urls:
driver.get(url)
data = driver.page_source
soup = BeautifulSoup(data, "html.parser")
divs = soup.findAll('div', attrs={'class': 'row'}) # 遍历所有的项
for div in divs:
# 'title'代表的是文字,'urls'代表的是图片的集合,'like'代表的是点赞数,'unlike'代表的是踩
item = {}
urls = [] item['like'] = div.find('span', attrs={'class': 'tucao-like-container'}).find('span').string
item['unlike'] = div.find('span', attrs={'class': 'tucao-unlike-container'}).find('span').string paragraph = div.find(attrs={'class': 'text'}).find("p") # 获取所有的图片链接
links = paragraph.select("a.view_img_link")
for link in links:
urls.append("http:" + link.get('href'))
item['urls'] = urls # 获取最开始的文字部分
title = re.search('<p>[\s\S]+?<a', str(paragraph)) if title is not None and title.group()[3:-8] is not None \
and title.group()[3:-8].find('view_img_link') == -1:
item['title'] = title.group()[3:-8]
else:
item['title'] = "" items.append(item) i = 1
j = 1
try:
for item in items:
# 插入新闻数据
cursor.execute(sql_news % (i, item['title'], int(item['like']), int(item['unlike'])))
# 插入图片数据
for tempUrl in item['urls']:
cursor.execute(sql_pics % (j, tempUrl, i))
j = j+1
i = i+1
db.commit()
except Exception as e:
print(e)
print(item)
db.rollback()
db.close()

注意点:

  • 在用pymysql的时候,如果插入的数据有中文,则在connect的时候需要设置charset,见13行
  • 44行在获取title的时候用了正则表达式,最开始直接用[.+]并不会匹配换行符,因此换成了[\s\S],\s匹配空白符,\S匹配非空白符,因此可以匹配所有的字符。
  • 最开始准备使用MySQLdb来操作数据库,但是python3不支持,于是换成了pymysql来操作数据库

至此,后台数据已经获取完成,接下来是后台接口的开发,准备采用Java的Servlet来实现后台接口的开发。

反思:

  • 对python语法掌握的不足,一些简单的语法需要通过查询才知道怎么用,需要找一个时间完整的学习一边python语法
  • 对正则表达式的使用不熟练,以后需要加强对正则表达式使用的练习
  • 本次代码仅作学习用,没有进行优化,也没有考虑到一些特殊的情况
  • 通过这次学习到了python语法+爬虫基本步骤+数据库的整体设计+解析网页源码
  • 如果title中有表情,保存数据库会报错,该问题正在解决

大家如果有什么疑问或者建议可以通过评论或者邮件的方式联系我,欢迎大家的评论~

仿9GAG制作过程(二)的更多相关文章

  1. 仿9GAG制作过程(一)

    有话要说: 准备开始学习Android应用程序的一个完整的设计过程.准备做一个仿9GAG的APP,前端界面设计+后台数据爬虫+后台接口设计,整个流程体验一遍.今天准备先把前端界面的框架给完成了. 成果 ...

  2. 仿9GAG制作过程(四)

    有话要说: 这次主要讲述主页面下拉刷新和上拉加载功能的实现. 主要是使用了SwipeRefreshLayout的布局方式,并在此基础上通过RecyclerView的特性增加了上拉加载的功能. 成果: ...

  3. 仿9GAG制作过程(五)

    有话要说: 在做完了数据展示功能之后,就想着完善整个APP.发现现在后台非常的混乱,有好多点都不具备,比方说:图片应该有略缩图和原图,段子.评论.点赞应该联动起来,段子应该有创建时间等. 于是就重新设 ...

  4. 仿9GAG制作过程(三)

    有话要说: 这次准备讲述后台服务器的搭建以及前台访问到数据的过程. 成果: 准备: 安装了eclipse 安装了Tomcat7 安装了数据库管理工具:Navicat 搭建服务器: 用eclipse直接 ...

  5. [PCB制作] 1、记录一个简单的电路板的制作过程——四线二项步进电机驱动模块(L6219)

    前言 现在,很多人手上都有一两个电子设备,但是却很少有人清楚其中比较关键的部分(PCB电路板)是如何制作出来的.我虽然懂点硬件,但是之前设计的简单系统都是自己在万能板上用导线自己焊接的(如下图左),复 ...

  6. Android实训案例(九)——答题系统的思绪,自己设计一个题库的体验,一个思路清晰的答题软件制作过程

    Android实训案例(九)--答题系统的思绪,自己设计一个题库的体验,一个思路清晰的答题软件制作过程 项目也是偷师的,决心研究一下数据库.所以写的还是很详细的,各位看官,耐着性子看完,实现结果不重要 ...

  7. BabyLinux制作过程详解

    转:http://www.360doc.com/content/05/0915/14/1429_12641.shtml BabyLinux制作过程详解 作者:GuCuiwen email:win2li ...

  8. ASP.NET Web API 过滤器创建、执行过程(二)

    ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...

  9. ASP.NET Web API 控制器创建过程(二)

    ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病 ...

随机推荐

  1. 私有云的难处—为什么需要CloudEngine?

    私有云的难处 ——我们为什么需要 CloudEngine? 郑昀 创建于2016/7/31 最后更新于2016/8/3 关键词: 容器.Docker.OpenStack.虚拟机.私有云.Mesos.配 ...

  2. NIO类库

    NIO概述 从JDK1.4开始,引入了新的I/O类库,它们位于java.nio包中,其目的在于提高I/O的操作效率.nio是new io的缩写. 参考文章:NIO BIO AIO区别 java.nio ...

  3. [Swift]LeetCode148. 排序链表 | Sort List

    Sort a linked list in O(n log n) time using constant space complexity. Example 1: Input: 4->2-> ...

  4. [Swift]LeetCode813. 最大平均值和的分组 | Largest Sum of Averages

    We partition a row of numbers A into at most K adjacent (non-empty) groups, then our score is the su ...

  5. [Swift]LeetCode983. 最低票价 | Minimum Cost For Tickets

    In a country popular for train travel, you have planned some train travelling one year in advance.  ...

  6. 调用链Cat介绍

    1. 调用链Cat 1.1. 调用链演进 1.2. 开源产品比较 1.3. 监控场景 1.4. cat的增值作用 1.5. cat典型报表 1.5.1. 应用报错大盘 1.5.2. 业务大盘 1.5. ...

  7. 【实战分享】又拍云 OpenResty / Nginx 服务优化实践

    2018 年 11 月 17 日,由 OpenResty 主办的 OpenResty Con 2018 在杭州举行.本次 OpenResty Con 的主题涉及 OpenResty 的新开源特性.业界 ...

  8. 线程安全(中)--彻底搞懂synchronized(从偏向锁到重量级锁)

    接触过线程安全的同学想必都使用过synchronized这个关键字,在java同步代码快中,synchronized的使用方式无非有两个: 通过对一个对象进行加锁来实现同步,如下面代码. synchr ...

  9. GraphQL 的前世今生

    GraphQL是什么 GraphQL是一种新的API标准,它提供了一种更高效.强大和灵活的数据提供方式.它是由Facebook开发和开源,目前由来自世界各地的大公司和个人维护.GraphQL本质上是一 ...

  10. RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2-新增锁定用户与解除锁定用户的功能

    锁定用户功能在现实应用场景中得到了大量的应用,当我们需要限制某用户的登录,又不能删除这个用户时就可以使用锁定功能,如:未授权的用户尝试错误密码错误过多可以尝试的用户进行锁定,又如ATM机上取钱时密码错 ...