爬取思路:爬取http://www.jokeji.cn/,得到一个html页面,分析此html页面,获得分类框里的所有分类的url地址,遍历每一个分类的url,爬取分类url的html网页,分析分类url网页,得到全部笑话网页列表,遍历笑话网页列表url,得到最终的包含一个一个笑话的html页面,获取笑话,存储到mysql数据库。
爬取我用的是Google浏览器,在这个网站下按F12就可以看到网页源代码了,此时要分析这个笑话大全的分类框的结构,以便使用python正则表达式获取到我们想要的信息。
一般筛选内容都会选择目标内容组件的上层容易唯一标识的组件,在这里我选择了<div class=”joketype l_left”>这个html,这个div可以包含所有分类的内容,然后再进行一次筛选就可以把所有url筛选出来了。到了分类子页面我看了一下url的规律,这个分类的url都是/listXX_1.htm开始,发现分类页面里面有个尾页的按钮的url刚好是结束,并且url的.htm前面的那个数字递增,所以就很好爬取所有笑话页面了,至于提取笑话就不再多说了,直接上所有代码。
mysql数据库存储模块代码,文件名为mysql.py。
import pymysql
def insert(joke):
#获取链接
conn=pymysql.connect(host='127.0.0.1',user='root',passwd='123456',db='python')
cur=conn.cursor()
#sql语句,%s是占位符(%s是唯一的,不论什么数据类型都使用%s)防止sql注入
sql='insert into joke(joke) VALUES(%s)'
#params=('eric','wuhan') #参数 插入单条
#li=[('a1','b1'),('a2','b2')] #批量插入参数
#reCount=cur.execute(sql,params)
reCount=cur.executemany(sql,joke) #批量插入
conn.commit() #提交,执行多条命令只需要commit一次就可以
cur.close()
conn.close()
def get_one():
#获取链接
conn=pymysql.connect(host='127.0.0.1',user='root',passwd='123456',db='python')
cur=conn.cursor()
sql1='select number from number'
reCount=cur.execute(sql1)
number=cur.fetchone()[0]+1
sql2='select joke from joke where id=%s'
reCount=cur.execute(sql2,number)
joke=cur.fetchone()[0]
sql3='update number set number=%s where number=%s'
params=(number,number-1)
reCount=cur.execute(sql3,params)
conn.commit()
cur.close()
conn.close()
爬虫代码,文件名为spider.py。
import urllib
from urllib import request
import re
import chardet
import mysql
import time
'''
找到http://www.jokeji.cn/list29_1.htm笑话列表
获取第一个笑话网页http://www.jokeji.cn/jokehtml/bxnn/2018080417455037.htm
遍历完所有笑话网页
获取下一个笑话列表,重复遍历,直至此分类笑话遍历完
遍历下一个分类
遇到不懂的问题?Python学习交流群:821460695满足你的需求,资料都已经上传群文件,可以自行下载!
'''
class Spider():
url='http://www.jokeji.cn/jokehtml/bxnn/2018073023294432.htm'
header = {
'User-Agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Mobile Safari/537.36',
'Accept-Encoding': '',
'Referer':'http://www.jokeji.cn/list29_1.htm'
}
classifys=[] #list集合,存储笑话分类url
#获取html文本
def __fetch_content(self):
cookie_html = request.Request(Spider.url,headers=Spider.header)
cookie_html = request.urlopen(cookie_html)
htmls=cookie_html.read()
#使用chardet获取到htmls的编码格式
encoding=chardet.detect(htmls)
encoding=encoding['encoding']
#不加ignore的时候总是出现字符转换错误,说明有非法字符,必须加上ignore忽略非法字符
htmls=htmls.decode(encoding,'ignore')
time.sleep(0.1)
return htmls
#获取笑话分类url
def __analysis_classify(self):
Spider.url='http://www.jokeji.cn/'
Spider.header['Referer']='http://www.jokeji.cn/'
htmls=self.__fetch_content()
root_pattern='<div class="joketype l_left">([\s\S]*?)</div>'
classify_pattern='<a href="([\s\S]*?)">'
root_html=re.findall(root_pattern,htmls)
Spider.classifys=re.findall(classify_pattern,str(root_html))
#获取当前页面里的所有笑话,返回一个tuple
def __analysis(self,htmls):
anchors=[]
root_pattern='<span id="text110">([\s\S]*?)</span>'
juck_pattern='<P>\d、([\s\S]*?)</P>'
root_html=re.findall(root_pattern,htmls)
for html in root_html:
jucks=re.findall(juck_pattern,html)
#替换换行符
c=re.compile('<[b|B][r|R]\s*/*>')
for i in jucks:
i=c.sub('\n',i)
anchors.append(i)
#i=i.replace('<BR>','\n')
return anchors
return anchors
#爬取原创笑话
def __analysis_yuanchuangxiaohua(self,url):
url='http://www.jokeji.cn'+url
pass
#爬取分类下的笑话
def __analysis_joke(self):
Spider.header['Referer']='http://www.jokeji.cn/'
root_pattern='<div class="list_title">([\s\S]*?)</div>'
page_pattern='<a href="([\s\S]*?)"\s*target="_blank"\s*>'
for classify in Spider.classifys:
try:
if '/yuanchuangxiaohua' in classify:
self.__analysis_yuanchuangxiaohua(classify)
classify='http://www.jokeji.cn'+classify
Spider.url=classify
htmls=self.__fetch_content()
#记录分类里面最大页面数
max_number=int(re.findall('[\s\S]*?(\d*?)\.htm">尾页</a>',htmls)[0])
#开始遍历每一大页,一大页包含很多小页面,小页面里面才是笑话
except BaseException:
continue
for bigpage_number in range(1,max_number+1):
try:
bigpage_url=classify
temp=re.compile('(\d*).htm')
#更改url,因为分类下每一大页都是有规律的,都是.htm前面的数字从1加到最大页面数
bigpage_url=temp.sub(str(bigpage_number)+'.htm',bigpage_url)
#替换url
Spider.url=bigpage_url
htmls=self.__fetch_content()
root_html=re.findall(root_pattern,htmls)
#获取一大页里面的小页面的url地址
pages=re.findall(page_pattern,root_html[0])
#遍历所有小页面url,获取其中的笑话
except BaseException:
continue
for page in pages:
try:
Spider.url='http://www.jokeji.cn'+page
htmls=self.__fetch_content()
tuples=self.__analysis(htmls)
#插入到数据库
mysql.insert(tuples)
except BaseException:
continue
def go(self):
self.__analysis_classify()
self.__analysis_joke()
spider=Spider()
spider.go()