时间:2023-07-04 06:48:02 | 来源:网站运营
时间:2023-07-04 06:48:02 来源:网站运营
教你如何用 Python 爬取网页制作电子书:作者简介:孙亖,软件工程师,长期从事企业信息化系统的研发工作,主要擅长后台业务功能的设计开发。
本文来自作者在 GitChat 上分享「如何用 Python 爬取网页制作电子书」主题内容。
# -*- coding: utf-8 -*-import scrapyclass XzxzbSpider(scrapy.Spider): name = 'xzxzb' allowed_domains = ['qidian.com'] start_urls = ['http://qidian.com/'] def parse(self, response): pass
start_urls 就是目录地址,爬虫会自动爬这个地址,然后结果就在下面的 parse 中处理。现在我们就来编写代码处理目录数据,首先爬取小说的主页,获取目录列表: def parse(self, response): pages = response.xpath('//div[@id="j-catalogWrap"]//ul[@class="cf"]/li') for page in pages: url = page.xpath('./child::a/attribute::href').extract() print url pass
获取网页中的 DOM 数据有两种方式,一种是使用 CSS 选择子,另外一种是使用 XML 的 xPath 查询。pages = response.xpath('//div[@id="j-catalogWrap"]//ul[@class="cf"]/li')
接着,遍历子节点,并查询 li 标签内 a 子节点的 href 属性,最后打印出来:for page in pages: url = page.xpath('./child::a/attribute::href').extract() print url
这样,可以说爬取章节路径的小爬虫就写好了,使用如下命令运行 xzxzb 爬虫查看结果:scrapy crawl xzxzb
这个时候我们的程序可能会出现如下错误:…ImportError: No module named win32api…
运行下面的语句即可:pip install pypiwin32
屏幕输出如下:> ...> [u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/wrrduN6auIlOBDFlr9quQA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Jh-J5usgyW62uJcMpdsVgA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/5YXHdBvg1ImaGfXRMrUjdw2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/fw5EBeKat-76ItTi_ILQ7A2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/KsFh5VutI6PwrjbX3WA1AA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/-mpKJ01gPp1p4rPq4Fd4KQ2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/MlZSeYOQxSPM5j8_3RRvhw2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/5TXZqGvLi-3M5j8_3RRvhw2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/sysD-JPiugv4p8iEw--PPw2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/xGckZ01j64-aGfXRMrUjdw2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/72lHOJcgmedOBDFlr9quQA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/cZkHZEYnPl22uJcMpdsVgA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/vkNh45O3JsRMs5iq0oQwLQ2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/ge4m8RjJyPH6ItTi_ILQ7A2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Y33PuxrKT4dp4rPq4Fd4KQ2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/MDQznkrkiyXwrjbX3WA1AA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/A2r-YTzWCYj6ItTi_ILQ7A2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Ng9CuONRKei2uJcMpdsVgA2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/Q_AxWAge14pMs5iq0oQwLQ2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/ZJshvAu8TVVp4rPq4Fd4KQ2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/hYD2P4c5UB2aGfXRMrUjdw2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/muxiWf_jpqTgn4SMoDUcDQ2'][u'//read.qidian.com/chapter/MuRzJqCY6MyoLoerY3WDhg2/OQQ5jbADJjVp4rPq4Fd4KQ2']> ...
爬取章节路径的小爬虫就写好了,但我们的目的不仅于此,我们接下来使用这些地址来抓取内容:# -*- coding: utf-8 -*-import scrapyclass XzxzbSpider(scrapy.Spider): name = 'xzxzb' allowed_domains = ['qidian.com'] start_urls = ['https://book.qidian.com/info/1010780117/'] def parse(self, response): pages = response.xpath('//div[@id="j-catalogWrap"]//ul[@class="cf"]/li') for page in pages: url = page.xpath('./child::a/attribute::href').extract_first() # yield scrapy.Request('https:' + url, callback=self.parse_chapter) yield response.follow(url, callback=self.parse_chapter) pass def parse_chapter(self, response): title = response.xpath('//div[@class="main-text-wrap"]//h3[@class="j_chapterName"]/text()').extract_first().strip() content = response.xpath('//div[@class="main-text-wrap"]//div[@class="read-content j_readContent"]').extract_first().strip() print title # print content pass
上一步,我们获取到了一个章节地址,从输出内容来看是相对路径,因此我们使用了yield response.follow(url, callback=self.parse_chapter),第二个参数是一个回调函数,用来处理章节页面,爬取到章节页面后我们解析页面和标题保存到文件。next_page = response.urljoin(url)yield scrapy.Request(next_page, callback=self.parse_chapter)
scrapy.Request 不同于使用 response.follow,需要通过相对路径构造出绝对路径,response.follow 可以直接使用相对路径,因此就不需要调用 urljoin 方法了。 def parse_chapter(self, response): title = response.xpath('//div[@class="main-text-wrap"]//h3[@class="j_chapterName"]/text()').extract_first().strip() content = response.xpath('//div[@class="main-text-wrap"]//div[@class="read-content j_readContent"]').extract_first().strip() # print title # print content filename = './down/%s.html' % (title) with open(filename, 'wb') as f: f.write(content.encode('utf-8')) pass
至此,我们已经成功的抓取到了我们的数据,但还不能直接使用,需要整理和优化。 def parse(self, response): pages = response.xpath('//div[@id="j-catalogWrap"]//ul[@class="cf"]/li') for page in pages: url = page.xpath('./child::a/attribute::href').extract_first() idx = page.xpath('./attribute::data-rid').extract_first() # yield scrapy.Request('https:' + url, callback=self.parse_chapter) req = response.follow(url, callback=self.parse_chapter) req.meta['idx'] = idx yield req pass def parse_chapter(self, response): idx = response.meta['idx'] title = response.xpath('//div[@class="main-text-wrap"]//h3[@class="j_chapterName"]/text()').extract_first().strip() content = response.xpath('//div[@class="main-text-wrap"]//div[@class="read-content j_readContent"]').extract_first().strip() # print title # print content filename = './down/%s_%s.html' % (idx, title) cnt = '<h1>%s</h1> %s' % (title, content) with open(filename, 'wb') as f: f.write(cnt.encode('utf-8')) pass
关键词:电子