转自本人博客园博客:https://www.cnblogs.com/JYU-hsy/p/9673454.html
目录
一、前言
二、何为爬虫
三、JD商品详情页的网页分析
3.1详情页上指向的其他URL
3.2商品名称、价格
四、简单爬虫框架
1.爬虫总调度程序
2.URL管理器
3.HTML下载器
4.HTML解析器
5.输出程序
五、源码
一、前言
本文适合有一定Python基础的同学学习Python爬虫,无基础请点击:慕课网——Python入门
申明:实例的主体框架来自于慕课网——Python开发简单爬虫
语言:Python2
IDE:VScode
二、何为爬虫
传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,然后下载队列中的URL地址对应的网页。解析后抓取网页内容,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。同时,它还会根据一定的搜索策略获取我们所需的信息并保存下来。最后为了展示我们爬到的数据,往往还会用HTML的表格或记事本保存我们所需要的数据。
简单来说,爬虫就是一门用来从互联网上自动获取我们所需数据的技术。
三、JD商品详情页的网页分析
入口URL选择为JD某商品详情页:https://item.jd.com/4224129.html
我们需要分析的内容主要有:
3.1详情页上指向的其他URL
我们打开https://item.jd.com/4224129.html,发现网页上还有很多指向其他商品的链接。
通过鼠标右键,查看元素,我们可以发现商品页面上的以上链接均为以下格式: //item.jd.com/数字.html
分析到此,我们就知道抓取网页内容时,从当前页面上抽取新的URL的方法了。
3.2商品名称、价格
同理,我们在商品名称和价格处点击鼠标右键查看元素
四、简单爬虫框架
1.爬虫总调度程序
即我们的main文件,以入口URL为参数爬取所有相关页面
2.URL管理器
维护待爬取和已爬取的URL列表
3.HTML下载器
主要功能是下载指定的url,这里用到了urllib2
4.HTML解析器
主要功能是获取网页上所需的URL和内容,用到BeautifulSoup
正则表达式的基础知识可以参见
re模块(正则表达式) - 人生不如戏 - 博客园
另外安利一个网站,在写正则表达式的时候可以先测试,很实用
正则表达式在线测试
5.输出程序
将爬取到的数据写入HTML文件中,利用HTML的table展示
五、源码
1.爬虫总调度程序
import url_manager, html_downloader, html_parser, html_outputerclass SpiderMain(object):def __init__(self):self.urls = url_manager.UrlManager()self.downloader = html_downloader.Html_DownloaDer()self.parser = html_parser.HtmlParser()self.outputer = html_outputer.HtmlOutputer()#爬虫调度程序def craw(self, root_url):count = 1#入口URL添加进URL管理器 self.urls.add_new_url(root_url)#启动循环,获取待扒取的URL,然后交给下载器下载页面,调用解析器解析页面while self.urls.has_new_url():try:new_url = self.urls.get_new_url()print 'craw',count, ':' ,new_urlhtml_cont = self.downloader.download(new_url)#得到新的URL列表和内容new_urls, new_data = self.parser.parse(new_url,html_cont)#新的URL存到URL管理器,同时进行数据的收集self.urls.add_new_urls(new_urls)self.outputer.collect_data(new_data)if count == 10:breakcount = count +1except:print 'craw dailed'#调用output_html展示爬取到的数据self.outputer.output_html()if __name__ == "__main__":#入口URLroot_url = "https://item.jd.com/4224129.html"obj_spider = SpiderMain()#启动爬虫obj_spider.craw(root_url)
2.URL管理器
class UrlManager(object):def __init__(self):#未爬取URL列表,已爬取URL列表self.new_urls = set()self.old_urls = set()#判断管理器中是否有新的待扒取的URLdef has_new_url(self):return len(self.new_urls) != 0#获取一个新的待扒取的URLdef get_new_url(self):#pop方法:获取列表中的一个URL并移除它new_url = self.new_urls.pop()self.old_urls.add(new_url)return new_url#向管理器添加一个新的URLdef add_new_url(self, url):if url is None:return#发现新的未添加的URL,则加入待扒取URL列表if url not in self.new_urls and url not in self.old_urls:self.new_urls.add(url)#向管理器添加批量个新的URLdef add_new_urls(self, urls):if urls is None or len(urls) == 0:returnfor url in urls:self.add_new_url(url)
3.HTML下载器
import urllib2class Html_DownloaDer():def download(self, url):if url is None:return None#调用urllib2库的urlopen方法获取 类文件对象(fd) response""" response = urllib2.urlopen(url)"""#调用urllib2库的Request方法创建request对象request = urllib2.Request(url)#添加数据request.add_data('a')#添加htp和header(伪装成浏览器)request.add_header('User-Agent','Mozilla/5.0')#发送请求获取结果response = urllib2.urlopen(request)#获取状态码,200表示成功if response.getcode() != 200:return Nonereturn response.read()
4.HTML解析器
from bs4 import BeautifulSoup
import re
import urlparseclass HtmlParser(object):def _get_new_urls(self, page_url, soup):new_urls = set()#获取所有的链接#格式如:<a target="_blank" title="华为(HUAWEI)..." href="//item.jd.com/12943624333.html">links = soup.find_all('a',href = re.compile(r"//item.jd.com/\d+\.htm"))#遍历转化为完整的URLfor link in links:new_url = link['href']new_full_url = urlparse.urljoin(page_url,new_url)#将结果存到一个新的列表里new_urls.add(new_full_url)return new_urlsdef _new_data(self, page_url, soup):res_data = {}#URLres_data['url'] = page_url#匹配标题#<div class="sku-name">华为(HUAWEI) MateBook X 13英寸超轻薄微边框笔记本(i5-7200U 4G 256G 拓展坞 2K屏 指纹 背光 office)灰</div>title_node = soup.find('div',class_ = "sku-name")res_data['title'] = title_node.get_text()#匹配价格#<div class="dd">#<span class="p-price"><span>¥</span><span class="price J-p-7430495">4788.00</span></span>"""下载的网页源码无价格信息<span class="price J-p-7430495"></span></span>!!!!!""" price_node = soup.find('span',class_ = re.compile(r"price\sJ\-p\-\d+"))res_data['price'] =price_node.get_text()return res_datadef parse(self, page_url, html_cont):if page_url is None or html_cont is None:returnsoup = BeautifulSoup(html_cont,'html.parser')new_urls = self._get_new_urls(page_url,soup)_new_data = self._new_data(page_url,soup)return new_urls, _new_data
5.输出程序
class HtmlOutputer(object):def __init__(self):self.datas = []def collect_data(self,data):if data is None:returnself.datas.append(data)def output_html(self):fout = open('output.html','w')fout.write("<html>")fout.write("<head>")fout.write('<meta charset="UTF-8">') fout.write("<body>")fout.write("<table>")#python默认编码是ascii,中文可能会乱码,故加上encode('utf-8')for data in self.datas:fout.write("<tr>")fout.write("<td>%s</td>" % data['url'])fout.write("<td>%s</td>" % data['title'].encode('utf-8'))fout.write("<td>%s</td>" % data['price'].encode('utf-8'))fout.write("</tr>")fout.write("</table>")fout.write("</body>")fout.write("</head>")fout.write("</html>")