「2022 年」崔庆才 Python3 爬虫教程 - 基础案例爬取实战( 二 )


这里我们引入了 requests 用来爬取页面,logging 用来输出信息,re 用来实现正则表达式解析,urljoin 用来做 URL 的拼接 。
接着我们定义了下日志输出级别和输出格式,接着定义了 BASE_URL 为当前站点的根 URL,TOTAL_PAGE 为需要爬取的总页码数量 。
好,定义好了之后,我们来实现一个页面爬取的方法吧,实现如下:
def scrape_page(url): logging.info('scraping %s...', url) try: response = requests.get(url) if response.status_code == 200: return response.text logging.error('get invalid status code %s while scraping %s', response.status_code, url) except requests.RequestException: logging.error('error occurred while scraping %s', url, exc_info=True)
考虑到我们不仅要爬取列表页,还要爬取详情页,所以在这里我们定义一个较通用的爬取页面的方法,叫做 scrape_page,它接收一个 url 参数,返回页面的 html 代码 。这里首先判断了状态码是不是 200,如果是,则直接返回页面的 HTML 代码,如果不是,则会输出错误日志信息 。另外这里实现了 requests 的异常处理,如果出现了爬取异常,则会输出对应的错误日志信息,我们将 logging 的 error 方法的 exc_info 参数设置为 True 则可以打印出 Traceback 错误堆栈信息 。
好了,有了 scrape_page 方法之后,我们给这个方法传入一个 url,正常情况下它就可以返回页面的 HTML 代码了 。
接着在这个基础上,我们来定义列表页的爬取方法吧,实现如下:
def scrape_index(page): index_url = f'{BASE_URL}/page/{page}' return scrape_page(index_url)
方法名称叫做 scrape_index,这个实现就很简单了,这个方法会接收一个 page 参数,即列表页的页码,我们在方法里面实现列表页的 URL 拼接,然后调用 scrape_page 方法爬取即可,这样就能得到列表页的 HTML 代码了 。
获取了 HTML 代码之后,下一步就是解析列表页,并得到每部电影的详情页的 URL 了,实现如下:
def parse_index(html): pattern = re.compile('<a.*?href="https://www.08ts.cn/(.*?)".*?>') items = re.findall(pattern, html) if not items: return [] for item in items: detail_url = urljoin(BASE_URL, item) logging.info('get detail url %s', detail_url) yield detail_url
在这里我们定义了 parse_index 方法,它接收一个 html 参数,即列表页的 HTML 代码 。
在 parse_index 方法里面,我们首先定义了一个提取标题超链接 href 属性的正则表达式,内容为:
<a.*?href="https://www.08ts.cn/(.*?)".*?>
在这里我们使用非贪婪通用匹配正则表达式 .*? 来匹配任意字符,同时在 href 属性的引号之间使用了分组匹配 (.*?) 正则表达式,这样 href 的属性值我们便能在匹配结果里面获取到了 。紧接着,正则表达式后面紧跟了 来标示这个 <a> 节点是代表电影名称的节点 。
好,现在有了正则表达式,那么怎么提取列表页所有的 href 值呢?使用 re 的 findall 方法就好了,第一个参数传入这个正则表达式构造的 pattern 对象,第二个参数传入 html,这样 findall 方法便会搜索 html 中所有能匹配该正则表达式的内容,然后把匹配到的结果返回,最后赋值为 items 。
如果 items 为空,那么我们可以直接返回空的列表,如果 items 不为空,那么我们直接遍历处理即可 。
遍历 items 得到的 item 就是我们在上文所说的类似 /detail/1 这样的结果 。由于这并不是一个完整的 URL,所以我们需要借助 urljoin 方法把 BASE_URL 和 href 拼接起来,获得详情页的完整 URL,得到的结果就类似 https://ssr1.scrape.center/detail/1 这样的完整的 URL 了,最后 yield 返回即可 。
这样我们通过调用 parse_index 方法并传入列表页的 HTML 代码就可以获得该列表页所有电影的详情页 URL 了 。
好,接下来我们把上面的方法串联调用一下,实现如下:
def main(): for page in range(1, TOTAL_PAGE + 1): index_html = scrape_index(page) detail_urls = parse_index(index_html) logging.info('detail urls %s', list(detail_urls))if __name__ == '__main__': main()
这里我们定义了 main 方法来完成上面所有方法的调用,首先使用 range 方法遍历了一下页码,得到的 page 就是 1-10,接着把 page 变量传给 scrape_index 方法,得到列表页的 HTML,赋值为 index_html 变量 。接下来再将 index_html 变量传给 parse_index 方法,得到列表页所有电影的详情页 URL,赋值为 detail_urls,结果是一个生成器,我们调用 list 方法就可以将其输出出来 。
好,我们运行一下上面的代码,结果如下:
2020-03-08 22:39:50,505 - INFO: scraping https://ssr1.scrape.center/page/1...2020-03-08 22:39:51,949 - INFO: get detail url https://ssr1.scrape.center/detail/12020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/22020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/32020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/42020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/52020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/62020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/72020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/82020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/92020-03-08 22:39:51,950 - INFO: get detail url https://ssr1.scrape.center/detail/102020-03-08 22:39:51,951 - INFO: detail urls ['https://ssr1.scrape.center/detail/1', 'https://ssr1.scrape.center/detail/2', 'https://ssr1.scrape.center/detail/3', 'https://ssr1.scrape.center/detail/4', 'https://ssr1.scrape.center/detail/5', 'https://ssr1.scrape.center/detail/6', 'https://ssr1.scrape.center/detail/7', 'https://ssr1.scrape.center/detail/8', 'https://ssr1.scrape.center/detail/9', 'https://ssr1.scrape.center/detail/10']2020-03-08 22:39:51,951 - INFO: scraping https://ssr1.scrape.center/page/2...2020-03-08 22:39:52,842 - INFO: get detail url https://ssr1.scrape.center/detail/112020-03-08 22:39:52,842 - INFO: get detail url https://ssr1.scrape.center/detail/12...


推荐阅读