如何在JavaScript源代码中选择元素?

时间:2016-07-05 03:25:54

标签: xpath scrapy

我需要在下面的JavaScript源代码中获取“html”键的值,该源代码由xpath('。// script [34]')提取并嵌入到html源页面中。

   <script>
        FM.view({
            "ns": "pl.content.homeFeed.index",
            "domid": "Pl_Official_MyProfileFeed__24",
            "css": ["style/css/module/list/comb_WB_feed_profile.css?version=73267f08bd52356e"],
            "js": "page/js/pl/content/homeFeed/index.js?version=dad90e594db2c334",
            "html": "                <div class=\"WB_feed WB_feed_v3\" pageNum=\"\" node-type='feed_list' module-type=\"feed\">\r\n...."
        })
    </script>

我不知道如何处理文本“FM.view”。

2 个答案:

答案 0 :(得分:2)

我会使用.re()从脚本中提取html键值:

>>> response.xpath("//script[contains(., 'Pl_Official_MyProfileFeed__24')]/text()").re(r'"html": "(.*?)"\n')
[0].strip()
u'<div class=\\"WB_feed WB_feed_v3\\" pageNum=\\"\\" node-type=\'feed_list\' module-type=\\"feed\\">\\r\\n..'

或者,您可以从脚本中提取完整对象,使用json加载它并获取html值:

>>> import json
>>> data = response.xpath("//script[contains(., 'Pl_Official_MyProfileFeed__24')]/text()").re(r'(?ms)FM\.view\((\{.*?\})\)')[0]
>>> obj = json.loads(data)
>>> obj['html'].strip()
u'<div class="WB_feed WB_feed_v3" pageNum="" node-type=\'feed_list\' module-type="feed">\r\n....'

注意正则表达式中的(?ms)部分 - 这是我们设置标志的方式 - 多行和dotall - 在这种情况下模式可以工作。

答案 1 :(得分:2)

这是使用js2xml包的正则表达式+ json的替代方法。

第一步是从HTML中获取<script>中的JavaScript语句。你可能已经迈出了这一步。在这里,我正在从您的输入HTML构建一个Scrapy选择器。在您的情况下,您可能正在使用回调中的response

>>> import scrapy
>>> import js2xml
>>> t = r'''   <script>
...         FM.view({
...             "ns": "pl.content.homeFeed.index",
...             "domid": "Pl_Official_MyProfileFeed__24",
...             "css": ["style/css/module/list/comb_WB_feed_profile.css?version=73267f08bd52356e"],
...             "js": "page/js/pl/content/homeFeed/index.js?version=dad90e594db2c334",
...             "html": "                <div class=\"WB_feed WB_feed_v3\" pageNum=\"\" node-type='feed_list' module-type=\"feed\">\r\n...."
...         })
...     </script>'''
>>> selector = scrapy.Selector(text=t, type='html')

第二步是使用js2xml.parse()构建JavaScript程序的树表示。你得到一个lxml树:

>>> js = selector.xpath('//script/text()').extract_first()
>>> jstree = js2xml.parse(js)
>>> jstree
<Element program at 0x7ff19ec94ea8>
>>> type(jstree)
<type 'lxml.etree._Element'>

>>> print(js2xml.pretty_print(jstree))
<program>
  <functioncall>
    <function>
      <dotaccessor>
        <object>
          <identifier name="FM"/>
        </object>
        <property>
          <identifier name="view"/>
        </property>
      </dotaccessor>
    </function>
    <arguments>
      <object>
        <property name="ns">
          <string>pl.content.homeFeed.index</string>
        </property>
        <property name="domid">
          <string>Pl_Official_MyProfileFeed__24</string>
        </property>
        <property name="css">
          <array>
            <string>style/css/module/list/comb_WB_feed_profile.css?version=73267f08bd52356e</string>
          </array>
        </property>
        <property name="js">
          <string>page/js/pl/content/homeFeed/index.js?version=dad90e594db2c334</string>
        </property>
        <property name="html">
          <string>                &lt;div class="WB_feed WB_feed_v3" pageNum="" node-type='feed_list' module-type="feed"&gt;&#13;
....</string>
        </property>
      </object>
    </arguments>
  </functioncall>
</program>

第三是从树中选择所需的对象。 在这里,它是FM.view()调用的第一个参数。即使您选择了1个节点(XPath返回节点集),在lxml树上调用.xpath()也会为您提供一个列表

# select the function call for "FM.view"
# and get first argument
>>> jstree.xpath('''
        //functioncall[
            function[.//identifier/@name="FM"]
                    [.//identifier/@name="view"]]
            /arguments
                /*[1]''')
[<Element object at 0x7ff19ec94ef0>]
>>> args = jstree.xpath('//functioncall[function[.//identifier/@name="FM"][.//identifier/@name="view"]]/arguments/*[1]')

第四,使用<object>js2xml.jsonlike.make_dict()转换为Python dict:

# use js2xml.jsonlike.make_dict() on that argument
>>> js2xml.jsonlike.make_dict(args[0])
{'ns': 'pl.content.homeFeed.index', 'html': '                <div class="WB_feed WB_feed_v3" pageNum="" node-type=\'feed_list\' module-type="feed">\r\n....', 'css': ['style/css/module/list/comb_WB_feed_profile.css?version=73267f08bd52356e'], 'domid': 'Pl_Official_MyProfileFeed__24', 'js': 'page/js/pl/content/homeFeed/index.js?version=dad90e594db2c334'}
>>> from pprint import pprint
>>> pprint(js2xml.jsonlike.make_dict(args[0]))
{'css': ['style/css/module/list/comb_WB_feed_profile.css?version=73267f08bd52356e'],
 'domid': 'Pl_Official_MyProfileFeed__24',
 'html': '                <div class="WB_feed WB_feed_v3" pageNum="" node-type=\'feed_list\' module-type="feed">\r\n....',
 'js': 'page/js/pl/content/homeFeed/index.js?version=dad90e594db2c334',
 'ns': 'pl.content.homeFeed.index'}
>>> 

最后,您只需使用该词典中的“html”键:

>>> jsdata = js2xml.jsonlike.make_dict(args[0])
>>> jsdata['html']
'                <div class="WB_feed WB_feed_v3" pageNum="" node-type=\'feed_list\' module-type="feed">\r\n....'
>>>